Hibernate 缓存介绍
hibernate缓存包括一级缓存,二级缓存以及查询缓存
一级缓存
一级缓存是Session的缓存,由于session对象的生命周期对应于一个事务,所有session的缓存是事务范围的缓存。第一级缓存是必须的,缓存中的每个持久类对象都有唯一的OID。无需做任何配置,hibernate自动维护。
当执行load/get/list/iterator/ filter/save/update/saveOrUpdate等方法时会把得到的实体对象放入一级缓存中(只支持实体对象缓存,不支持属性的缓存),当在同一个session范围内执行load/get/iterator等查询语句查询缓存过的数据时(不包括list),Hibernate不会去数据库中查询。
1.load
在执行session.load时,Hibernate首先从当前session的一级缓存中获取id对应的值,在获取不到的情况下,将根据该对象是否配置了二级缓存来做相应的处理,如配置了二级缓存,则从二级缓存中获取id对应的值,如仍然获取不到则还需要根据是否配置了延迟加载来决定如何执行,如未配置延迟加载则从数据库中直接获取,在从数据库获取到数据的情况下,Hibernate会相应的填充一级缓存和二级缓存,如配置了延迟加载则直接返回一个代理类实例,只有在访问实例时(get)才进行数据库查询的操作。
2.get
session.get与session.load的行为基本一致,只是当缓存中没有需要的对象时,session.get会直接从数据库加载数据(session.load返回代理类实例)。
3.Query.list
list取到结果集后会填充一级、二级和查询缓存,但是list方法查询数据时不会使用一级缓存和二级缓存的值,除非配置了查询缓存。
4.Query.iterator
在执行iterator时,先向数据库发起的是select id from这样的语句,获取符合查询条件的id,之后在进行iterator.next调用时才会根据id查看缓存中是否存在数据,如果缓存中没有会发起session.load的调用获取实际的数据。所有最理想状态下iterator会发出一条查询id的sql语句,但在最差的情况下会发出N+1条查询语句。
一级缓存管理常用api
evit(obj) : 将指定的持久化对象从一级缓存中清除,释放对象所占用的内存资源,指定对象从持久化状态变为脱管状态,从而成为游离对象.
clear() : 将一级缓存中的所有持久化对象清除,释放其占用的内存资源
contains(obj): 判断指定的对象是否存在于一级缓存中.
flush() :刷新一级缓存区的内容,使之与数据库数据保持同步.
因为save方法支持缓存,大批量数据添加时每save一个对象就往缓存里放,如果对象足够多内存肯定要溢出。一般的做法是先判断一下save了多少个对象,如果save了20个对象就手动清空缓存。
1 for (int i=0; i<100; i++) { 2 Student student = new Student(); 3 student.setName("student" + i); 4 session.save(student); 5 //20条更新一次 6 if (i % 20 == 0) { 7 //清空缓存前将缓存中的数据与数据库同步 8 session.flush(); 9 //清空缓存 10 session.clear(); 11 } 12 } 13
二级缓存
二级缓存需要sessionFactory来管理,它是进程级的缓存,所有是session共享的,二级缓存比较复杂,一般用第三方产品,官方推荐使用ehcache。
配置ehcache二级缓存
1.添加jar包
1 <dependency> 2 <groupId>org.hibernate</groupId> 3 <artifactId>hibernate-ehcache</artifactId> 4 <version>4.3.0.Final</version> 5 </dependency>
2.Hibernate配置文件(hibernate4.0,不同版本hibernate下provider_class会有不同)
1 <property name="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</property> 2 <!-- 默认即为true --> 3 <property name="hibernate.cache.use_second_level_cache">true</property>
3.ehcache配置文件ehcache.xm(根路径下)
1 <?xml version="1.0" encoding="UTF-8"?> 2 <ehcache> 3 <defaultCache 4 maxElementsInMemory="50000" 5 eternal="false" 6 overflowToDisk="true" 7 timeToIdleSeconds="3600" 8 timeToLiveSeconds="3600" 9 /> 10 11 <cache name="com.zlt.hibernatedemo.Student" 12 maxElementsInMemory="50000" 13 eternal="true" 14 /> 15 </ehcache>
4.类添加二级缓存功能
方法一:配置hibernate.cfg.xml
<class-cache usage="read-only" class="com.zlt.hibernatedemo.Student"/>
方法二:配置hbm文件
在<id>属性前加入<cache usage="read-only"/>
二级缓存缓存的key为id,value为实体对象。一般load(),iterate()使用到二级缓存,list()需要结合查询缓存使用,二级缓存在数据发生任何变化(新增、更新、删除)的情况下都会自动的被更新。
二级缓存管理常用api
session.setCacheMode(CacheMode.IGNORE):禁止使用二级缓存
evict(Class arg0, Serializable arg1): 将某个类的指定ID的持久化对象从二级缓存中清除,释放对象所占用的资源.
例如sessionFactory.evict(Student.class, new Integer(1));
evict(Class arg0) 将指定类的所有持久化对象从二级缓存中清除,释放其占用的内存资源.
例如sessionFactory.evict(Student.class);
evictCollection(String
arg0)
将指定类的所有持久化对象的指定集合从二级缓存中清除,释放其占用的内存资源.
例如sessionFactory.evictCollection("Grade.students");
查询缓存是专为Query的list方法设计的。对于iterate()方法,无论是查询对象属性还是对象本身,查询缓存用与不用都没有区别
配置查询缓存
1.查询缓存必须要在hibernate.cfg.xml中显示启用:<property name="hibernate.cache.use_query_cache">true</property>
2.在代码中如果要用到查询缓存(无论是写还是读缓存),都要进行开启操作,可通过Query的setCacheable(true)方法开启;
查询缓存的生命周期与Session无关(可以跨Session查询),当查询关联的表发生改变,那么查询缓存的生命周期结束(delete、update、modify)
开启查询缓存,并用Query查询对象的属性(可以是一个或多个)时,采用Query的list方法可以把得到的属性集合写入查询缓存中。如果查询缓存已经有了该对象的属性,那么就不会发出SQL而直接从查询缓存中取出来;
二级缓存和查询缓存关系
1.关闭查询缓存,开启二级缓存时:
第二次查询属性时iterate只会发出获取id列表的sql,list会发出和第一次一样的请求实体的sql。
2.开启查询缓存,关闭二级缓存
如果开启查询缓存并通过list接口查询对象,在首次查询时会发出SQL从数据库中获取对象,同时将对象的id列表放入查询缓存中;如果再次用查询缓存查询对象,则会根据该对象的id(session.load)发出SQL从数据库中加载对象(这时会发出N条SQL语句)
3.开启查询缓存,开启二级缓存
第二次查询属性时iterate只会发出获取id列表的sql,list不发sql(此时的list接口有了读二级缓存的能力)
以上说明iterate只和二级缓存有关,list和二级缓存和查询缓存都有关。
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。