”一天一节“之Hibernate的缓存机制
Hibernate的缓存机制
Hibernate的数据缓存根据它的作用范围或生命周期的不同大致分为两种:一级缓存和二级缓存,下面分别说明下两个缓存:
1. 一级缓存
Hibernate的一级缓存作用范围是在同一个session下,也就是在同一个事务级别下,它随着session的销亡而销亡。Hibernate的一级缓存一般情况下是由hibernate自行维护的,如果我们要手动去维护,hibernate也提供了两个方法:
session.evict(Object obj);//将某个特定的的对象从一级缓存中清除出去
Session.clear(); //清除一级缓存中的所有对象
Hibernate一级缓存的实现原理,也是非常简单的,这里针对hibernate2来说明下,在Session接口的实现类SessionImpl中定义了许多的Map对象,这些Map维护这与当前session相关联的所以PO状态,当我们查询实体对象时,会首先根据id和加载类与在对应的Map结构中匹配,如果命中则直接讲结果对象返回,否则到数据库中去加载数据,并将加载对象放入这些Map中进行管理。另外这些Map结构都是私有的,所以说明了一级缓存是随着session的销亡而销亡的。
2. 二级缓存
Hibernate的二级缓存作用范围是一个SessionFactory下的所有session实现共享,其随着SessionFactory的关闭而消亡。
虽然说二级缓存可以带来性能上的优化但是还是要因事而论,比如一个聊天系统里提供一个查看用户历史聊天记录,可能要查询近几个月所有的记录,而且基本上这些记录不可能被共享(本用户只查看自己的记录),如果这里使用缓存管理,并且是多用户并行操作,可想而知会给内存带来什么后果!
Hibernate本身其实并没有对二级缓存提供很好的实现(只提供了一个基于hashtable的简单实现以供调试),而是为众多第三方实现提供了接口。下面来看个基于EHCache的二级缓存配置实现:
1. 导入ehcache.1.2.3.jar包;
2. 配置ehcache.xml;
<?xml version="1.0" encoding="UTF-8"?> <ehcache> <diskStore path="java.io.tmpdir"/> <defaultCache maxElementsInMemory="10000" <!-- 缓存最大数目 --> eternal="false" <!-- 缓存是否持久 --> overflowToDisk="true" <!-- 是否保存到磁盘,当系统当机时--> timeToIdleSeconds="300" <!-- 当缓存闲置n秒后销毁 --> timeToLiveSeconds="180" <!-- 当缓存存活n秒后销毁--> diskPersistent="false" diskEXPiryThreadIntervalSeconds= "120"/> </ehcache>
3. 在Hibernate配置文件中设置:
<!-- 配置 hibernate 二级缓存 --> <property name="hibernate.cache.use_second_level_cache">true </property> <property ame="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider </property>
<!--EndFragment-->
4.在Hbm文件中添加<cache usage="read-only"/>
测试代码:
public static void main(String[] args) { long star = System.currentTimeMillis(); Session session = HibernateUtils.getSession(); Transaction tr = session.beginTransaction(); Query query = session.createQuery("from User3"); System.out.println(((User3)query.iterate().next()).getName()); tr.commit(); session.close(); Session session1 = HibernateUtils.getSession(); Transaction tr1 = session1.beginTransaction(); Query query1 = session1.createQuery("from User3"); System.out.println(((User3)query1.iterate().nex()).getName()); tr1.commit(); session1.close(); System.out.println( System.currentTimeMillis() - star +" ms"); }
<!--EndFragment-->
<!--EndFragment-->