hibernate缓存
1、hibernate 的一级缓存是由session提供的,对同一个id进行两次load,不会发送两条sql给数据库,但是session关闭的时候,一级缓存就失效了。
2、二级缓存是SessionFactory级别的全局缓存,只要sessionFactory没有关闭,hibernate会首先考虑去缓存中load数据,如果缓存中不存在我们想要的数据或者只有一部分我们想要的数据,hibernate才会去数据库里load数据。它可以利用不同的缓存类库(hibernate本身不提供现成的),比如ehcache、oscache等。需要设置 hibernate.cache.provider_class,我们这里用ehcache,
hibernate.cache.provider_class=net.sf.hibernate.cache.EhCacheProvider,
在要缓存的类的配置文件中指定缓存的策略
<cache usage="read-write"/>(我一般都用这个模式)
如果使用查询缓存,加上 hibernate.cache.use_query_cache=true
设置ehcache.xml,配置如下:
<ehcache>
<diskStore path="C:\\temp"/>
<defaultCache
maxElementsInMemory="10000"
eternal="false"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
overflowToDisk="true" />
<cache name="com.eric.model.Customers"
maxElementsInMemory="1"
eternal="false"
timeToIdleSeconds="300"
timeToLiveSeconds="600"
overflowToDisk="true" />
<cache name="com.eric.model.Order"
maxElementsInMemory="10000"
eternal="false"
timeToIdleSeconds="300"
timeToLiveSeconds="600"
overflowToDisk="true" />
<cache name="customerQueries"
maxElementsInMemory="1000"
eternal="false"
timeToIdleSeconds="300"
timeToLiveSeconds="600"
overflowToDisk="true" />
</ehcache>
如果没有对某个具体的类做相应的策略指定,会默认使用defaultCache的配置。
如果要指定缓存的策略,需要在每次查询之后加上query.setCacheRegion("customerQueries")
1.Class的缓存:对于一条记录,也就是一个PO来说,是根据ID来找的,缓存的key就是ID,value是POJO。无论list,load还是iterate,只要读出一个对象,都会填充缓存。但是list不会使用缓存,而iterate会先取数据库select id出来,然后一个id一个id的load,如果在缓存里面有,就从缓存取,没有的话就去数据库load。
2.查询缓存:只要更新过一个表,那么凡是涉及到这个表的查询缓存就失效了,因此查询缓存的命中率可能会比较低。
先来考察一下缓存的作用:缓存之所以可以命中,前提条件是该数据被使用的非常频繁,同时更新的可能性相当小,如果数据会频繁修改,那么毫无疑问,缓 存不会带来任何好处。明确了这一点,我们就明白什么对象应该进行缓存了。显然,对于那些经常会被访问到的小批量的诸如基础信息,用户和权限信息是非常适合进行缓存的,这些数据我们可以在应用启动的时候就执行一次list方法查询, 进行缓存填充(例如写一个InitBean类进行数据缓存初始化),此外在数据被修改的时候,再次执行list方法,进行缓存填充。而在使用这些数据的其他地方,统统使用iterator方法。这样就可以实现所谓的第一次查询使用 List,随后的查询使用iterator了。
Hibernate在进行批处理的时候存在一定的劣势(很大的劣势),比如在批处理的时候hibernate无法用一条语句来完成,只能以一个实体为单位进行处理,如果要更新一万条数据就要查出一万次,然后update一万次。另外因为hibernate存在缓存机制,load出来的数据会存放在缓存中,而一级缓存我们无法程序控制,这也带来了一些系统开销,这也是hibernate在批处理的时候存在劣势的原因。这种情况下存在几种解决方式:
1)立即flush缓存,然后利用session的evit使对象移除(治标不治本)。
2)利用jdbc实现(hibernate转jdbc还是比较容易的)。
3)建存储过程。
hibernate的缓存策略(抄来的)
只读缓存(read-only):没有什么好说的
读/写缓存(read-write):程序可能要的更新数据
不严格的读/写缓存(nonstrict-read-write):需要更新数据,但是两个事务更新同一条记录的可能性很小,性能比读写缓存好
事务缓存(transactional):缓存支持事务,发生异常的时候,缓存也能够回滚,只支持jta环境,这个我没有怎么研究过
读写缓存和不严格读写缓存在实现上的区别在于,读写缓存更新缓存的时候会把缓存里面的数据换成一个锁,其他事务如果去取相应的缓存数据,发现被锁住了,然后就直接取数据库查询。
在hibernate2.1的ehcache实现中,如果锁住部分缓存的事务发生了异常,那么缓存会一直被锁住,直到60秒后超时。
不严格读写缓存不锁定缓存中的数据。