HIbernate 5.3 (十)

10 篇文章 0 订阅
9 篇文章 0 订阅
本文详细介绍了Hibernate的缓存机制,包括一级缓存的自动管理及何时清除,二级缓存的开启、配置与策略,以及查询缓存的使用。通过实例展示了Ehcache的配置和管理,强调了缓存对提高应用程序性能的重要性。
摘要由CSDN通过智能技术生成

Hibernate 缓存的引出

Hibernate是一个持久化框架,经常需要访问数据库。如果我们能够降低应用程序对物理数据库访问的频次,那会提供应用程序的运行性能。缓存内的数据是对物理数据源中的数据的复制,应用程序运行时先从缓存中读写数据。

Hibernate 缓存的一级缓存
Hibernate 如何缓存的效果

Hibernate一级缓存又被成为“Session的缓存”。Session缓存是内置的,不能被卸载,是事务范围的缓存。在一级缓存中,持久化类的每个实例都具有唯一的OID。

		   Configuration con = new Configuration().configure();
		   SessionFactory sf = con.buildSessionFactory();
		   Session ss = sf.openSession();
		   Transaction tt = ss.beginTransaction();
		   News n1 = ss.load(News.class, 1);
		   News n2 = ss.load(News.class, 2);
		   tt.commit();
		   ss.close();
		   sf.close();

在这段代码中,我们对我们调用两次load 方法,可以看后台打印的SQL语句,可以发现,就是select 语句 只有一句,这实际上就使用了缓存。实际上,第一次Session 加载对象的时候,它就存放被当前工作单元中加载的对象,也就是News这个对象对应表的数据。(这里涉及数据库的快照,这里我们就简单理解)(注意这个只是针对于查询,如果是插入、删除还是需要执行相应的SQL语句的)。

你需要记住的事,平常我们save、load的操作都是在session中,并不是真正的操作数据库。

Hibernate 何时清除缓存
  1. commit() 方法被调用时 。
  2. 显示的调用session 的 flush方法。

只有清除缓存,才是将数据真正的写入到数据库中。

Session 加载对象后会为对象值类型的属性复制一份快照。当Session 清理缓存时,比较当前对象和它的快照就可以知道那些属性发生了变化,进行相应的修改。

Hibernate 二级缓存

之前已经说过Session 级别的一级缓存,二级缓存是基于SessionFactory。

SessionFactory级别的二级缓存是全局性的(一般在整个应用中,我们SessionFactory 对象只会有一个),应用的所有Session都共享这个二级缓存。不过SessionFactory级别的缓存默认是关闭的,必须由程序显式开启。一旦在应用中开启了二级缓存,当Session需要抓取数据时, Session将会优先从二级缓存抓取。

开启二级缓存

在Hibernate 配置文件:

		<property name="hibernate.cache.use_second_level_cache" >true</property>  

指定二级缓存的实现类

这里实现类可以是多种,下面以EhCache 为例。

	<property name="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.EhCacheRegionFactory</property>


Ehache 配置
Ehache 导包

导入EhCache的Jar包,可以在hibernate 下载的文件中找到

D:\hibernate\hibernate-release-5.3.0.Beta1\lib\optional\ehcache //对应自己的路径去查找,我用5.3 里面有2个,都拷到项目下。
ehcache 配置文件路径

需要添加Ehcache 的配置文件到项目,最好是和Hibernate 配置放在一个目录,以免有问题。配置文件可以直接从下面路径找到,直接修改相应的属性即可。

D:\hibernate\hibernate-release-5.3.0.Beta1\project\etc
配置文件属性介绍
<defaultCache
        maxElementsInMemory="10000" 
        eternal="false"
        timeToIdleSeconds="120"
        timeToLiveSeconds="120"
        overflowToDisk="false"
        />
  • maxElementsInMemory 设置缓存中最多放多少对象
  • eternal 设置缓存是否永久有效
  • timeToIdleSeconds 设置对象多少秒没有被使用就clean
  • timeToLiveSeconds 设置对象缓存长时间
  • overflowToDisk 是否将缓存对象放到硬盘上,保存路径由diskStore 决定
对实体、集合启用二级缓存

两种方式:

  1. 修改要使用缓存的实体的映射文件。在持久化映射文件的<clas…>元素、或<set…/>、<ist…>等集合元素内使用<cache…/>元素指定缓存策略。
  2. 在hibernate.cfg.xml文件中使用<class-cache…/>或<collection-cache…/>元素对指定持久化类、集合属性启用二级缓存。
二级缓存策略
  • 只读策略(read-only) :如果应用程序只需读取持久化实体的对象,无须对其进行修改,那么就可以对其设置“只读”缓存策略。这是最简单、也最实用的缓存策略。
  • 读/写缓存(read/write) :如果应用程序需要更新数据,那就需要使用“读/写”缓存策略了。如果应用程序要求使用“序列化事务(serializable transaction)”的隔离级别,那就绝不能使用这种缓存策略。
  • 非严格读/写(nonstrict read/write) :如果应用程序只需要偶尔更新数据(也就是说,两个事务同时更新同一记录的情况很少见),也不需要十分严格的事务隔离, 那么比较适合使用非严格读/写缓存策略。
  • 事务缓存( transactional) :Hibernate的事务缓存策略提供了全事务的缓存支持。
二级缓存测试
java.util.List<Object> list = ss.createQuery("from Person p1").list();
		   Session ss1 = sf.openSession();
		   Person  p1 = ss1.load(Person.class,4);
		   System.out.println(p1.getName());
		   Person  p2 = ss.load(Person.class,3);
		   System.out.println(p2.getName());

打印的数据,查询语句只执行一次。

当Hibernate 首先查询出所有的数据,它会将这些实体存放在二级缓存中,当你下次查询某一个实体的时候,只要缓存还在,Hibernate会优先进入缓存中去拿。

在使用Ehcache 的时候,当你在发布或者重新部署的时候,一定要重启tomcat,否则Ehcache manager 会报什么已经create错误。

缓存查找的方式,先到一级缓存中查找,如果开启二级缓存,在二级缓存中查找,最后到数据库中查找。

Session级别的一级缓存是局部缓存,它只对当前Session有效; SessionFactory 级别的二-级缓存 是全局缓存,它对所有的Session都有效。

管理缓存和统计缓存
管理缓存
一级缓存管理

对于hibernate 持久化操作,执行的对象都将被放入Session级别的一级缓存中,在 Session调用flush(方法(该方法把所有缓存数据一次性 flush到数据库)或close(方法之前,这些对象将一直缓存在一级缓存中。

在某些特殊的情况下,例如正在处理一个大对象 (它占用的内存开销非常大), 可能需要从一级缓存中去掉这个大对象或集合属性,可以调用Session的evict(Object object)方法,将该对象从一级缓存中剔除出去。

为了判断某个对象是否处于Session缓存中,可以借助于Session提供的contains(Object object)方法,该方法返回一个boolean值, 用于标识某个实例是否处于当前Session的缓存中。

			Person  p2 = ss.load(Person.class,3);
		   System.out.println(ss.contains(p2));//true 
		   ss.evict(p2);
		   System.out.println(ss.contains(p2));//false
		   Person  p3 = ss.load(Person.class,3);//光load 是不会触发sql 执行的,必须使用该对象
		   System.out.println(p3.getName());

可以看出,在第一次查询出Person 对象,由于剔除缓存,第二次查询相同的对象,需要再进行一次查询。

如果想把所有的对象都从Session缓存中彻底清除,调用Session的clear方法即可。

二级缓存管理

类似地, Hibermate同样提供了方法来操作SessionFactory的二级缓存所缓存的实体。SessionFactory提供了一个getCache方法,该方法的返回值是Cache对象,通过该对象来进行缓存管理。

前提:开启二级缓存

           Cache cache = sf.getCache();
		   Person  p2 = ss.load(Person.class,3);
		   cache.evict(Person.class);//从二级缓存中剔除Person 所有实例
		   //cache.evict(Person.class,3);//从二级缓存剔除指定实例
		   //cache.evictAll();
		   System.out.println(cache.contains(Person.class,3));//查询某个实例是否在二级缓存中
		   ss.close();
           Session ss1  =  sf.openSession();
		   Person  p3 = ss1.load(Person.class,3);
		   System.out.println(p3.getName());
二级缓存统计
开启二级缓存统计配置
<property name="hibernate.generate_statistics">true</property>
<property name="hibernate.cache.use_structured_entries">true</property>
获取二级缓存的数据
Map map = sf.getStatistics().getSecondLevelCacheStatistics("com.example.test.bean.Person").getEntries();//这里必须全限名,否则会报空指针异常
                    System.out.println(map.toString());

实际上,缓存也不是多牛逼的东西,也就是在某个地方(内存、磁盘)开辟空间,用来存放某些常用的数据。我们这里通过统计,缓存中该Person的二级缓存对象。

查询缓存

一级、二级缓存都是对整个实体进行缓存,它不会缓存普通属性,如果想对普通属性进行缓存,则可以考患使用查询缓存。

对于查询缓存来说,它缓存的key就是查询所用的HQL或SQL语句,需要指出的是: 查询缓存不仅要求所使用的HQL语句、SQL 语句相同,甚至要求所传入的参数也相同,Hibermate 才能直接从查询缓存中取得数据

开启查询缓存
		<property name="hibernate.cache.use_query_cache">true</property>

查询缓存的例子
java.util.List<Person> list = ss.createQuery("select p.name from Person p").setCacheable(true).list();
		   System.out.println(list.size());//setCacheable,开启查询缓存
		   
		   java.util.List<Person> list1 = ss.createQuery("select p.name from Person p").setCacheable(true).list();
		   System.out.println(list1.size());//sql、hql获取的属性和参数都没有变,但是还是需要setCacheable,否则不会从查询缓存中拿
		   
		   
		   java.util.List<Person> list2 = ss.createQuery("select p1.id from Person p1").list();
		   System.out.println(list2.size());//更换sql 的属性,无法从查询缓存中获取
		   
		   Iterator it = ss.createQuery("select p.name from Person p").setCacheable(true).iterate();
		   //该例子给查询对象设置iterator方法,尽管sql没变,依然无法查询缓存
		   
		   while(it.hasNext()){
			   System.out.println(it.next());

		   }

参考学习

参考学习

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值