Hibernate 包括二个级别的缓存,默认的总是启用Session级别的一级缓存,可选的 SessionFactory 级别的二级缓存,Session级别的一级缓存,但应用保存持久化实体、修改持久化实体时,Session 并不会立即把这种改变 flush 到数据库中,只有程序显示的调用 flush 方法,或者程序关闭 Session 时才会把这些改变一次性的flush到底层数据库。
- 开启二级缓存,需要在 hibernate.cfg.xml 配置文件中设置如下属性:
<property name="hibernate.cache.use_second_level_cache">true</property>
在开启二级缓存后,还需要配置二级缓存的具体实现,Hibernate 提供了三中缓存实现:
- ConcurrentHashMap 缓存,实现类为 org.hibernate.testing.cache.CachingRegionFactory,缓存类型为内存(该缓存只用于测试,不推荐实际项目中使用)
- EhCache 缓存,实现类为 org.hibernate.cache.ehcache.EhCacheRegionFactory,缓存类型为内存、磁盘、事务性、支持群集
- Infinispan 缓存,实现类为 org.hibernate.cache.infinispan.InfinispanRegionFactory,缓存类型为事务性、支持群集
Hibernate.cfg.xml 配置文件中增加如下属性,设置缓存类型:
<property name="hibernate.cache.region.factory_class">[缓存的具体实现类]</property>
要使用 EhCache 缓存,需要复制 Hibernate 目录下的 lib/optional/ehcache 子目录的 jar 包,主要依赖的 jar包如下:
- ehcache-core-2.4.3.jar
- hibernate-ehcache-4.3.11.Final.jar
- slf4j-api-1.6.1.jar
- commons-logging-1.2.jar(需要额外下载:http://commons.apache.org/proper/commons-logging/download_logging.cgi)
- backport-util-concurrent.jar(需要额外下载:https://sourceforge.net/projects/backport-jsr166/files/latest/download)
- 增加配置文件 ehcache.xml 整个配置文件可以在 Hibernate 的 projectetc 路径下找到,示例配置如下:
<ehcache>
<diskStore path="java.io.tmpdir"/>
<defaultCache
maxElementsInMemory="10000"
eternal="false"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
overflowToDisk="true"
/>
</ehcache>
配置说明如下:
- diskStrore:保存路径配置,path 的值有 user.home(用户的主目录可以使用)、user.dir(用户当前的工作目录)、java.io.tmpdir(默认临时文件路径)
- maxElementsInMemory:设置缓存中最多可以放多少个对象
- eternal:设置缓存是否永久有效
- timeToIdleSeconds:设置缓存对象多少秒没有被使用就会被清理掉
- timeToLiveSeconds:设置缓存对象在过期前可以缓存多少秒
- overflowToDisk:内存中的缓存已达到 maxInMemory 限制,是否可以溢出到磁盘
- diskPersistent:设置缓存对象是否被持久化到硬盘中,保存路径由<diskStore…/>配置决定
- diskExpiryThreadIntervalSeconds:磁盘失效线程运行时间间隔,默认是120秒。
- diskSpoolBufferSizeMB:这个参数设置DiskStore(磁盘缓存)的缓存区大小。默认是30MB。每个Cache都应该有自己的一个缓冲区。
- memoryStoreEvictionPolicy:当达到maxElementsInMemory限制时,Ehcache将会根据指定的策略去清理内存。默认策略是LRU(最近最少使用)、FIFO(先进先出)或是LFU(较少使用)
修改要使用缓存的持久化类文件,使用 Hibernate 提供的 @Cache 注解修饰持久化类,或者使用该注解修饰集合属性,也可以在 hibernate.cfg.xml 文件中使用<class-cache…/>元素对指定的持久化类启用二级缓存,示例配置及代码如下:
<class-cache usage="read-only" class="[缓存持久类完成名称]"/>
二级缓存可以设定以下 4 种类型的并发访问策略, 每一种访问策略对应一种事务隔离级别
- nonstrict-read-write(非严格读写):不保证缓存与数据库中数据的一致性,提供 Read Uncommited 事务隔离级别, 对于极少被修改, 而且允许脏读的数据, 可以采用这种策略
- read-write(读写型):提供 Read Commited 数据隔离级别.对于经常读但是很少被修改的数据, 可以采用这种隔离类型, 因为它可以防止脏读
- Transactional(事务型):仅在受管理环境下适用. 它提供了 Repeatable Read 事务隔离级别. 对于经常读但是很少被修改的数据, 可以采用这种隔离类型, 因为它可以防止脏读和不可重复读
- read-only(只读型):提供 Serializable 数据隔离级别, 对于从来不会被修改的数据, 可以采用这种访问策略
public static void main(String[] args) {
Session curSession = hibernateUtils.openSession();
Calendar calendar = Calendar.getInstance(Locale.CHINA);
try {
// 启用了二级缓存,在查询时需要开启事务
curSession.beginTransaction();
List list = curSession.createQuery("SELECT trm FROM TransitRecordModel trm").list();
System.out.println("Query Size=" + list.size());
curSession.getTransaction().commit();
// 从缓存读取,不查询数据库
TransitRecordModel recordModel = (TransitRecordModel) curSession.load(TransitRecordModel.class,new Integer(259));
System.out.println("RecordID=" + recordModel.getRecordID());
} finally {
if (curSession != null) {
curSession.close();
}
i}
- 管理缓存,Session 级别的一级缓存是局部缓存,只对当前Session有效;SessionFactory 级别的二级缓存是全局缓存,他对所有的Session都有效。
- Session 级别的一级缓存,所有操作的实体,使用 save、update、saveOrUpate、load、get、 list、iterate或者scroll 返回获取一个对象,改对象都会放入Session级别的一级缓存,在Session 调用 flush 或者 close 方法之前,这些对象一直缓存在一级缓存,如果想提前释放缓存,可以调用Session.evict 方法移除某个缓存,或者Session.clear 清除所有缓存
- SessionFactory 级别的二级缓存,如果要对二级缓存进行管理,可以调用 SessionFactory.getCache 方法,获取 cache对象,通过cache的 evictEntity、evictEntityRegion、evictCollection、 evictCollectionRegion 方法来管理缓存
- 统计缓存,开启二级缓存的统计功能,可以查询二级缓存的内容并提供了一些工具方法来分析二级缓存的效果
- 启用二级缓存的统计,在 hibernate.cfg.xml 文件增加如下配置:
<!-- 开启二级缓存的统计功能 -->
<property name="hibernate.generate_statistics">true</property>
<!-- 设置使用结构化方式来维护缓存项-->
<property name="hibernate.cache.use_structured_entries">true</property>
- 通过调用 SessionFactory 类的 getStatistics 返回 Statistics 类,通过 Statistics类可以访问工具方法,来获取缓存效果