配色: 字号:
Hibernate缓存
2015-06-10 | 阅:  转:  |  分享 
  
Hibernate缓存



一级缓存

二级缓存

查询缓存



参考:http://www.blogjava.net/tbwshc/articles/380013.html





一级缓存

◆hibernate是一个线程对应一个session,每个session一个一级缓存。



一级缓存生命周期很短,和session生命周期一样,事务提交或回滚了,我们称session就关闭了,生命周期结束了。

一级缓存也称session级的缓存或事务级缓存。



◆缓存主要是用于查询

Load:同一个session中,发出两次load方法查询,第二次查询第一次相同的数据,第二次load方法就是从缓存里取数据,不会发出sql语句到数据库里查询。



get:同一个session,发出两次get方法查询,第二次查询第一次相同的数据,第二次不会发出sql语句查询数据库,而是到缓存里取数据。



iterater查询:第一次iterate查询会发出N+1条sql语句,第一条sql语句查询所有的id,然后根据id查询实体对象,有N个id就发出N条语句查询实体。

第二次iterate查询,却只发一条sql语句,查询所有的id,然后根据id到缓存里取实体对象,不再发sql语句到数据库里查询了。



◆一级缓存只缓存实体对象



//iterate查询普通属性,一级缓存不会缓存

iter=session.createQuery

("selects.namefromStudentswheres.id<5").iterate();



//iterate查询对象,一级缓存会缓存

iter=session.createQuery

("fromStudentswheres.id<5").iterate();



◆session间不能共享一级缓存的数据



◆先save保存实体对象,再用load方法查询刚刚save的实体对象,则load方法不会发出sql语句到数据库查询的,而是到缓存里取数据,因为save方法也支持缓存。当然前提是同一个session



◆大批量数据添加时,会造成内存溢出的,因为save方法支持缓存,每save一个对象就往缓存里放,如果对象足够多内存肯定要溢出。一般的做法是先判断一下save了多少个对象,如果save了20个对象就对缓存手动的清理缓存,这样就不会造成内存溢出。



注意:清理缓存前,要手动调用flush方法同步到数据库,否则save的对象就没有保存到数据库里。



注意:大批量数据的添加还是不要使用hibernate,这是hibernate弱项。可以使用jdbc(速度也不会太快,只是比hibernate好一点),或者使用工具产品来实现,比如oracle的OracleSQLLoader,导入数据特别快。





二级缓存:



◆二级缓存需要sessionFactory来管理,是进程级别的缓存,多个session(多个线程)是共享的。



◆二级缓存比较复杂,一般用第三方的产品,hibernate只提供了一个简单的实现,用hashtable实现的



◆长时间不改变的数据才放到二级缓存



◆配置使用,EHCache缓存产品

(1)引入EHCache的jar包。



Hibernate_HOME\lib\optional\ehcache\ehcache-1.2.3.jar



Ehcache用的是Apache的Logging,添加jar包.

commons-logging-1.1.1.jar



(2)配置缓存策略:ehcache.xml(放类路径下,如src下)



//默认配置,所有的类都遵循这个配置






//缓存里可以放10000个对象



maxElementsInMemory="10000"



//过不过期,如果是true就是永远不过期



eternal="false"



//一个对象被访问后多长时间还没有访问就失效(120秒还没有再次访问就失效)



timeToIdleSeconds="120"



//对象存活时间(120秒),如果设置永不过期,这个就没有必要设了



timeToLiveSeconds="120"



//溢出的问题,如果设成true,缓存里超过10000个对象就保存到磁盘里



overflowToDisk="true"



/>





//我们也可以对某个对象单独配置:






maxElementsInMemory="100"



eternal="false"



timeToIdleSeconds="10000"



timeToLiveSeconds="10000"



overflowToDisk="true"



/>





(3)配置hibernate中集成使用EHCache缓存产品。

在hibernate.cfg.xml配置文件中配置缓存。



true



org.hibernate.cache.EhCacheProvider





写入false将不用二级缓存



(4)手动指定哪些实体类的对象放到二级缓存。(两种方法)

A、在hibernate.cfg.xml配置



//在标签里,在标签后配置


usage="read-only"/>



B、在实体类映射文件中配置(指定此实体二级缓存)



//在标签里,标签前配置





(5)缓存策略(常用以下两种)

A、read-only(常用):表示如果数据放到缓存,就不能再修改了

效率好,但是可能出现脏数据的问题(对象的数据被修改了,但是缓存却没有变)。

脏数据解决方法只能依赖缓存的超时



B、read-write:当持久化对象发生变化时,缓存里面就会跟着变化,数据库中也改变了。

这种方式需要加上锁,效率比read-only慢。



◆二级缓存必须让sessionfactory管理,让sessionfactory来清除。



sessionFactory.evict(Student.class);//清除二级缓存中所有student对象

sessionFactory.evict(Student.class,1);//清除二级缓存中id为1的student对象





◆查询数据后会默认放到二级和一级缓存中,可以控制查询出来的数据不放到二级缓存里面

session.setCacheMode(CacheMode.IGNORE);//禁止将一级缓存中的数据往二级缓存里放。



◆大批量的数据添加时可能会出现溢出,解决办法是每当有20个对象后就清理一次一级缓存。如果我们使用了二级缓存,光清理一级缓存是不够的,还要禁止一二级缓存交互。即在save方法前调用session.setCacheMode(CacheMode.IGNORE)。



◆二级缓存也不存放普通属性的查询数据,只存放实体对象。



◆session级别的缓存(一级缓存)对性能提高没有太大的意义,因为生命周期太短了。







查询缓存(很少用)



◆用Query的list方法查询,默认会把查询数据放入缓存,但不会使用缓存



◆配置list方法查询使用缓存

(1)hibernate.cfg.xml文件里配置打开“查询缓存”:



true



(2)手动启用查询缓存。调用Query接口的setCacheable(true)方法来启用。



Listnames2=(List)session2

.createQuery("selectc.namefromCategoryc")

.setCacheable(true)//启用查询缓存,每次list查询前都要调用这句代码

.list();



◆常见用途:查询缓存可存放实体对象的普通属性的数据,还存放查询实体对象的id。



◆查询缓存的生命周期不确定,当它关联的表发生修改,查询缓存的生命周期就结束。这里表的修改指的是通过hibernate修改,并不是通过数据库客户端软件登陆到数据库上修改。



◆查询缓存意义不是很大,查询缓存说明白了就是存放由list方法或者iterate方法查询的数据,我们在查询时很少出现完全相同的条件查询,这就是说命中率低,这样的缓存里的数据总是变化的。除非多次查询都是查询相同条件的数据,也就是说返回的结果总是一样,这样的缓存配置才有意义。
献花(0)
+1
(本文系常宁老男孩首藏)