Hibernate二级缓存的使用「建议收藏」

Hibernate二级缓存的使用「建议收藏」一、Hibernate共有两级缓存        Session级别缓存—-一级缓存(事务范围)        SessionFactory级别缓存—-二级缓存(进程范围) SessionFactory级别缓存        内置:Hibernate自带的,不可卸载.通常在Hibernate的初始化阶段,Hibernate会把映射

大家好,又见面了,我是你们的朋友全栈君。

一、Hibernate 共有两级缓存

         Session级别缓存 —- 一级缓存(事务范围)

         SessionFactory 级别缓存 —- 二级缓存(进程范围)

 

SessionFactory级别缓存

         内置:Hibernate 自带的, 不可卸载. 通常在 Hibernate 的初始化阶段, Hibernate 会把映射元数据和预定义的 SQL 语句放到 SessionFactory 的缓存中, 映射元数据是映射文件中数据的复制,而预定义 SQL 语句时 Hibernate 根据映射元数据推到出来的. 该内置缓存是只读的.

         外置:需要去配置第三方缓存插件(hibernate内部没有二级缓存实现),在默认情况下, SessionFactory不会启用这个缓存插件. 外置缓存中的数据是数据库数据的复制, 外置缓存的物理介质可以是内存或硬盘

        

二级缓存结构

         二级缓存包含 :类级别缓冲区、集合级别缓存区、更新时间戳缓冲区、查询缓存

                   注:有些人将查询缓存 称为是Hibernate 第三级缓存 ,查询缓存依赖于二级缓存,比二级缓存功能更加强大。

二级缓存的并发策略

         为了便于记忆,理解二级缓存 事务并发策略对应 事务隔离级别

         非严格读写(Nonstrict-read-write)

         读写型(Read-write)(用的最多)

         事务型(Transactional)

         只读型(Read-Only) 

适用二级缓存

         二级缓存适用于很少被修改的数据或者不是很重要的数据, 允许出现偶尔的并发问题。我们可以通过缓      存性能监控(通过适用次数判断),测试是否应该使用二级缓存

二级缓存支持四种 : EHCache 、OSCache 、 SwarmCache 和 JBossCache

                   * 本地数据库使用 EHCache 、OSCache

                   * 分布式数据库使用(企业) SwarmCache 和 JBossCache (支持集群范围缓存)

         EHCache:可作为进程范围内的缓存, 存放数据的物理介质可以是内存或硬盘, 对Hibernate的查询缓 存提供了支持

         OpenSymphony:可作为进程范围内的缓存, 存放数据的物理介质可以是内存或硬盘, 提供了丰富的缓存数据过期策略, 对Hibernate的查询缓存提供了支持

         SwarmCache: 可作为集群范围内的缓存, 但不支持 Hibernate 的查询缓存

         JBossCache:可作为集群范围内的缓存, 支持 Hibernate 的查询缓存

缓存插件支持的并发访问策略

Hibernate二级缓存的使用「建议收藏」

二级缓存快速入门

         1)导入jar包 hibernate 每个版本jar包中自带相关二级缓存jar包

                   ehcache除了需要导入自己的jar包,还需要依赖backport-util-concurrent 和 commons-logging

          Hibernate二级缓存的使用「建议收藏」

         2)在hibernate.cfg.xml开启二级缓存

                   <property name=”hibernate.cache.use_second_level_cache“>true</property>

         3)配置二级缓存提供商

                   <property name=”hibernate.cache.provider_class“>org.hibernate.cache.EhCacheProvider</property>

         4)配置二级缓存并发策略

                   方法一:在 hbm 映射文件中配置

                   <classname=”cn.itcast.query.Customer” table=”customer”catalog=”hibernate3day4″ >

                            <cacheusage=”read-write”/>

                   方法二:在hibernate.cfg.xml 文件中配置  

                   <class-cacheusage=”read-write” class=”cn.itcast.query.Customer”/>类级别的缓存

                   <class-cacheusage=”read-write” class=”cn.itcast.query.Order”/>类级别的缓存

                   <collection-cacheusage=”read-write” collection=”cn.itcast.query.Customer.orders”/>集合级别的缓存

         5)配置二级缓存的核心配置文件ehcache.xml

                   将ehcache.jar中ehcache-failsafe.xml 改名为ehcache.xml后复制到src就可以了。

        

二级缓存操作

案例一 : 证明二级缓存是存在的与类级别缓冲区的散装数据结构    

         对于一级缓存来说存储的是对象的地址,而地址引用的是内存中的实体类。

         对于二级缓存来说存储的是对象的属性散装数据(存在其类级别缓冲区中)。当要获取二级缓存中的数 据的时候,他会根据这些数据(id、name)重新组装成为一个对象(customer)。

         <class-cacheusage=”read-write” class=”cn.itcast.query.Customer”/>


 例:// 测试二级缓存是存在的 、类级别缓存数据是散装数据结果 public void demo1() { Session session = HibernateUtils.getCurrentSession(); Transaction transaction = session.beginTransaction(); // 查询结果 会被 保存一级缓存 ,当开启二级缓存后,也会保存到二级缓存 Customer customer1 = (Customer) session.get(Customer.class, 1); System.out.println(customer1); // 当再次查询的时候,因为一级缓存是存在,就从一级缓存直接获得 Customer customer2 = (Customer) session.get(Customer.class, 1); System.out.println(customer2); //由于获得当前线程绑定的session,所以就不需要关闭Session,当session关闭后,一级缓存清空。 transaction.commit(); //当再次需要数据的时候,获得当前线程绑定的session,再次开启事务 session = HibernateUtils.getCurrentSession(); transaction = session.beginTransaction(); // 不会产生SQL ,因为数据 可以从二级缓存找到 Customer customer3 = (Customer) session.get(Customer.class, 1); System.out.println(customer3); transaction.commit(); } 案例二 : 测试 get/load 可以读取二级缓存数据, Query的list方法 只能存,不能取 例:@Test // 测试Query的list方法只能向二级缓存保存数据,不能读取二级缓存 public void demo2() { Session session = HibernateUtils.getCurrentSession(); Transaction transaction = session.beginTransaction(); // Query的list 会将查询结果 存入二级缓存 List<Customer> customers = session.createQuery("from Customer").list(); System.out.println(customers); transaction.commit(); // session 关闭,一级缓存清空 session = HibernateUtils.getCurrentSession(); transaction = session.beginTransaction(); // Query 的list 不会读取二级缓存 List<Customer> customers2 = session.createQuery("from Customer").list(); System.out.println(customers2); transaction.commit(); session = HibernateUtils.getCurrentSession(); transaction = session.beginTransaction(); // 不会产生SQL ,因为Query 已经将数据保存到二级缓存,get/load可以读取二级缓存 Customer customer = (Customer) session.get(Customer.class, 1); System.out.println(customer); transaction.commit(); } 案例三 : 集合级别缓存区存储原理 (只会缓存OID ,数据保存类级别缓冲区中 ) <collection-cache usage="read-write" collection="cn.itcast.query.Customer.orders"/> 例:public void demo3() { Session session = HibernateUtils.getCurrentSession(); Transaction transaction = session.beginTransaction(); //查询客户,将其存入类级别的缓存 Customer customer = (Customer) session.get(Customer.class, 1); System.out.println(customer.getOrders().size()); //这里查询了订单集合,也会将散装数据保存到二级缓存,另外将id缓存到集合级别缓冲区。 for (Order order : customer.getOrders()) { System.out.println(order.getAddress()); } transaction.commit(); session = HibernateUtils.getCurrentSession(); transaction = session.beginTransaction(); Customer customer2 = (Customer) session.get(Customer.class, 1); // 这里再次查询order就不会产生新的SQL语句,他会根据在集合级别缓冲区的id对比后,到类级别 缓冲区找到散装的数据进行组合 System.out.println(customer2.getOrders().size()); for (Order order : customer.getOrders()) { System.out.println(order.getAddress()); } transaction.commit(); 如果将hibernate.cfg.xml中<class-cache usage="read-write" class="cn.itcast.query.Order"/> 注释掉,会产生额外10条SQL,原因是order的类级别缓存区缓存不了数据了,再次根据id到类级别缓冲区查找数据就没有了。才会去编写sql进行查询 } 案例四 :一级缓存更新会同步到二级缓存 例:@Test public void demo4() { Session session = HibernateUtils.getCurrentSession(); Transaction transaction = session.beginTransaction(); // 数据放入一级缓存和二级缓存 Customer customer = (Customer) session.get(Customer.class, 1); System.out.println(customer); //修改一级缓存数据 customer.setCity("石家庄"); // 一级缓存同步到二级缓存 transaction.commit(); session = HibernateUtils.getCurrentSession(); transaction = session.beginTransaction(); // 查询的是修改后的数据 Customer customer2 = (Customer) session.get(Customer.class, 1); System.out.println(customer2);//city为石家庄 transaction.commit(); } 案例五 :关于将二级缓存数据保存到硬盘上 当缓存的数据特别多的时候就需要将数据缓存到硬盘上,在ehcache.xml中通过配置 <diskStore path="java.io.tmpdir"/> 指定缓存数据硬盘的位置。 // 打印临时文件目录 public void demo5() { //获取实际路径方法:java.io.tmpdir 是 key System.out.println(System.getProperty("java.io.tmpdir")); } 

         将 C:\ehcache 配置临时文件存放目录 (建议win7 同学们不要用c 盘目录)

         ehcache.xml 提供  <defaultCache> 是二级缓存默认配置 (对所有缓存都有效)

                   通过 <cache name=”cn.itcast.query.Customer” > 该配置只对Customer 缓存有效

          <defaultCache

           maxElementsInMemory=”10000″ 内存中最大元素数量(当内存中的对象数量超过这个数,才会缓存到硬盘)

            eternal=”false”  缓存数据是否永久有效

            timeToIdleSeconds=”120″ 设置对象空闲最长时间 ,超过时间缓存对象如果没用,就会回收

           timeToLiveSeconds=”120″ 设置对象存活最长时间, 无论对象是否使用,到时间就会回收

           overflowToDisk=”true”  当内存缓存数据达到上限,是否缓存到硬盘

           maxElementsOnDisk=”10000000″  硬盘上最大缓存对象数量

           diskPersistent=”false”  当jvm结束时是否持久化对象 truefalse 默认是false

           diskExpiryThreadIntervalSeconds=”120″ 专门用于清除过期对象的监听线程的轮询时

           memoryStoreEvictionPolicy=”LRU”

     />

案例六: 测试更新时间戳缓存区域 
例:public void demo7() {
		Session session = HibernateUtils.getCurrentSession();
		Transaction transaction = session.beginTransaction();
		// 查询customer信息,放入二级缓存,并且记录了时间为t1
		Customer customer = (Customer) session.get(Customer.class, 1); 
		System.out.println(customer);
		// 这样修改数据库数据是不行的,因为修改一级缓存 自动同步 二级缓存
		// customer.setCity("济南"); 
		//如果这样改就不通过缓存了,并且记录时间为t2
 session.createQuery("update Customer set city='济南' where id = 1").executeUpdate(); 
		transaction.commit();

		session = HibernateUtils.getCurrentSession();
		transaction = session.beginTransaction();
		//比较 t2 > t1,若果 修改时间在缓存时间之后,证明数据被修改了,就会 重新生成SQL进行查询
		Customer customer2 = (Customer) session.get(Customer.class, 1);
		System.out.println(customer2);
		transaction.commit();
	}

Query 接口的iterate 方法

         当获得iterator 迭代器时,返回代理对象,当中数据只有OID

         在访问每个元素时,优先查找二级缓存,如果找不到,生成SQL 语句

例:public void demo8() {		Session session = HibernateUtils.getCurrentSession();		Transaction transaction = session.beginTransaction();		// 查询前10条订单,放入二级缓存		List<Order> orders = session.createQuery("from Order where id < 11").list();		transaction.commit();		session = HibernateUtils.getCurrentSession();		transaction = session.beginTransaction();		// 查询前15条订单,只会查询小于16的OID 返回代理对象 Iterator<Order> iterator = session.createQuery("from Order where id < 16").iterate();  		// 前十个订单,来自二级缓存,不会生成SQL		while (iterator.hasNext()) {			System.out.println(iterator.next().getAddress());		}		transaction.commit();	}

 

查询缓存操作

查询缓存和二级缓存关系 

         查询缓存是对二级缓存 进一步增强,可以缓存任何查询语句的结果。

         二级缓存查询结果,比如以OID作为key,以对象作为Value 进行缓存,查询缓存以SQL语句为      key,以查询结果作为Value

使用步骤

1) 配置开启查询缓存在hibernate.cfg.xml

         <property name=”hibernate.cache.use_query_cache“>true</property> 

                   (注意查询缓存,必须要先开启二级缓存)

2) 在程序中通过Query 的setCacheable(true)开启查询缓存

例:public void demo9() {
		Session session = HibernateUtils.getCurrentSession();
		Transaction transaction = session.beginTransaction();
		// 查询所有客户的姓名,这里没有OID,所以二级缓存做不到这点
		Query query = session.createQuery("select name from Customer");
		query.setCacheable(true); // 启用查询缓存
		List list = query.list(); // 将查询结果 放入了查询缓存
		System.out.println(list);
		transaction.commit();

		session = HibernateUtils.getCurrentSession();
		transaction = session.beginTransaction();
		//在查询缓存的取数据的时候也要开启查询缓存
		query = session.createQuery("select name from Customer");
		query.setCacheable(true); // 启用查询缓存
		List list2 = query.list(); // 从查询缓存 获得结果
		System.out.println(list2);
		transaction.commit();
	}

二级缓存的性能检测

         缓存性能的监控主要是通过访问二级缓存的次数来判断二级缓存的效率,测试是否应该使用二级缓存。

步骤:

1、 在hibernate.cfg.xml 将 hibernate.generate_statistics 配置true 启用 性能检测

                   <property name=”hibernate.generate_statistics“>true</property>

2、 使用SessionFactory 提供方法进行检测

         二级缓存

          sessionFactory.getStatistics().getSecondLevelCacheHitCount(); 二级缓存命中次数

          sessionFactory.getStatistics().getSecondLevelCacheMissCount();二级缓存丢失次数

          hitCount/ (hitCount+missCount) 二级缓存命中率

         查询缓存

         sessionFactory.getStatistics().getQueryCacheHitCount()查询缓存命中次数

         sessionFactory.getStatistics().getQueryCacheMissCount()查询缓存丢失次数

         queryCacheHitCount /(queryCacheHitCount + queryCacheMissCount); 查询缓存命中率

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/142536.html原文链接:https://javaforall.net

(0)
上一篇 2022年5月23日 下午2:40
下一篇 2022年5月23日 下午3:00


相关推荐

  • css中visiblity和display异同

    visiblity是设置元素的可见性,即可见/隐藏;隐藏后元素所占有位置保留;display是设置元素按什么样的方式来显示,是按块显示,显示成一条线的形式,显示为“消失”等等,当display

    2021年12月21日
    48
  • SecureCRTPortable(CRT)快捷键方法

    SecureCRTPortable(CRT)快捷键方法1.添加按钮,以进入beeline为例1)选中按钮栏2)3)beeline\r\p\p!connectjdbc:hive2://jh01:10000\rroot\r123456\r2.查找历史命令Ctrl+r

    2022年6月10日
    63
  • 七大查找算法

    七大查找算法1 顺序查找 2 二分查找 3 插值查找 4 斐波那契查找 5 树表查找 6 分块查找 7 哈希查找查找是在大量的信息中寻找一个特定的信息元素 在计算机应用中 查找是常用的基本运算 例如编译程序中符号表的查找 本文简单概括性的介绍了常见的七种查找算法 说是七种 其实二分查找 插值查找以及斐波那契查找都可以归为一类 插值查找 插值查找和斐波那契查找是在

    2026年3月18日
    3
  • phpstorm激活码2021。3[在线序列号]

    phpstorm激活码2021。3[在线序列号],https://javaforall.net/100143.html。详细ieda激活码不妨到全栈程序员必看教程网一起来了解一下吧!

    2022年3月19日
    222
  • 思科交换机路由器配置命令大全

    思科交换机路由器配置命令大全交换机基本状态 switch ROM 状态 路由器是 rommonhostna 用户模式 hostname 特权模式 hostname config 全局配置模式 hostname config if 接口状态交换机设置命令口令设置 switchenable 进入特权模式 switch configtermin 进入全局配置模式 switch config hostname 设置交换机的主机名 switch config enablesecret 设置特权加密口令 swi

    2026年3月17日
    1
  • Android ListView那些事

    Android ListView那些事ListView是我们在开发Android程序时用得比较多的一种widget,通常用来展示多条数据,这里,我对ListView的一些功能点作一个简单介绍。1. Cachecolorhint默认情况下,Android中的View的背景都是透明的,这是一个合理的设计,但是,当渲染到屏幕上时,这会引入许多的计算,因为所有的child的背景是透明的,这就意味着当ListView绘制它的chil

    2022年7月22日
    12

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号