Hibernate整合EHCache插件实现二级缓存 图片看不了?点击切换HTTP 返回上层
在《Hibernate二级缓存的并发访问策略和常用插件》教程介绍的几种常用的二级缓存插件中,EHCache 缓存插件是理想的进程范围的缓存插件。本小节将以 EHCache 缓存插件为例,介绍二级缓存的配置和使用。本节在教程前几节实例的基础上进行整合,具体步骤如下:
图 1 EHCache的下载
从图 1 中可以看出,目前 EHCache 的最新版本为 ehcache-3.7,本教程使用的是 ehcache-2.10.5,单击图中 Ehcache 2.x 下方的链接,即可下载此版本的 EHCache。下载并解压后,在压缩包文件中找到 ehcache-2.10.5.jar,将其复制到 hibernateDemo05 项目的 lib 目录中,并发布到类路径下即可。
<class-cache> 标签用于指定将哪些数据存储到二级缓存中,其中 usage 属性表示指定缓存策略。需要注意的是,<class-cache> 标签必须放在 <mapping> 标签的后面。
图 2 testCache() 方法的测试结果
从图 2 中可以看到,控制台只输出了一个查询 SQL,这说明 Hibernate 只在数据库中查询了一次。而下面的 true、false 和 true 是三次比较输出的结果。详细解释具体如下。
1)在上述代码中,开启了两个 Session 和事务,从第一个 Session 中获取 p1 对象时,由于一级缓存和二级缓存中没有相应的数据,需要从数据库中查询,所以发出了 SQL 语句。
2)查询出 p1 对象后,p1 对象会保存到一级缓存和二级缓存中。当获取 p2 对象时,因为 Session 没有关闭,所以会从一级缓存中取出该对象。由于 p1 和 p2 对象都保存在一级缓存中,而且指向的是同一实体对象,所以第一次输出结果为true。
3)接着提交事务 tx1,并关闭 session1,此时一级缓存中的数据会被清除。
4)接下来开启第二个 Session 和事务,获取 p3 对象,此时控制台没有产生 SQL 语句是因为 p3 对象是从二级缓存中获取的。取出后,二级缓存会将数据同步到一级缓存中,这时 p3 对象又在一级缓存中存在了。
5)因为 p3 对象是从二级缓存中获取的,而二级缓存中存储的都是对象的散装数据,它们会重新 new 出一个新的对象,所以第二次输出的结果为 false。
6)最后获取 p4 对象时,由于一级缓存中已经存在了 Person 对象,Hibernate 会直接从一级缓存中获取,所以输出结果为 true。
1. 引入 EHCache 相关的 JAR 包
读者可以从官方网址 http://www.ehcache.org/downloads/ 中下载 EHCache 的 JAR 包,成功访问后的页面显示如图 1 所示。图 1 EHCache的下载
从图 1 中可以看出,目前 EHCache 的最新版本为 ehcache-3.7,本教程使用的是 ehcache-2.10.5,单击图中 Ehcache 2.x 下方的链接,即可下载此版本的 EHCache。下载并解压后,在压缩包文件中找到 ehcache-2.10.5.jar,将其复制到 hibernateDemo05 项目的 lib 目录中,并发布到类路径下即可。
2. 引入 EHCache 的配置文件 ehcache.xml
读者可以直接从 Hibernate 的解压包的 hibernate-distribution-3.6.10.Final\project\etc 目录中找到 ehcache.xml,找到后,将此文件复制到项目的 src 目录下。ehcache.xml 文件中的主要代码如下所示:<?xml version="1.0" encoding="UTF-8"?> <ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd" updateCheck="false"> <diskStore path="java.io.tmpdir/Tmp_EhCache" /> <defaultCache eternal="false" maxElementsInMemory="10000" overflowToDisk="false" diskPersistent="false" timeToIdleSeconds="1800" timeToLiveSeconds="259200" memoryStoreEvictionPolicy="LRU" /> <cache name="cloud_user" eternal="false" maxElementsInMemory="5000" overflowToDisk="false" diskPersistent="false" timeToIdleSeconds="1800" timeToLiveSeconds="1800" memoryStoreEvictionPolicy="LRU" /> </ehcache>在上述配置代码中,各个元素作用如下表所示:
名称 | 说明 |
---|---|
<diskStore>元素 | 用于设置缓存数据文件的存储目录 |
<defaultCache>元素 | 用于设置缓存的默认数据过期策略。 |
<cache>元素 | 用于设置具体的命名缓存的数据过期策略。 |
maxElementsInMemory 属性 | 用于设置缓存对象的最大数目 |
eternal 属性 | 用于指定是否永不过期,true 为不过期,false 为过期。 |
timeToIdleSeconds 属性 | 用于设置对象处于空闲状态的最大秒数。 |
timeToLiveSeconds 属性 | 用于设置对象处于缓存状态的最大秒数。 |
overflowToDisk 属性 | 用于设置内存溢出时是否将溢出对象写入硬盘。 |
3. 启用二级缓存
在 Hibernate 的核心配置文件中启用二级缓存,并指定哪些实体类需要存储到二级缓存中。其配置代码如下所示:<property name ="hibernate.cache.use_second_level_cache">true </property> <property name ="hibernate.cache.provider_class"> org.hibernate.cache.EhCacheProvider </property > <mapping resource ="com/mengma/domain/Person.hbm.xml"/> <class-cache usage ="read-write" class ="com.mengma.domain.Person"/>在上述配置代码中,hibernate.cache.use_second_level_cache 用于开启二级缓存,hibernate.cache.provider_class 用于指定二级缓存的供应商。
<class-cache> 标签用于指定将哪些数据存储到二级缓存中,其中 usage 属性表示指定缓存策略。需要注意的是,<class-cache> 标签必须放在 <mapping> 标签的后面。
4. 创建测试类
在 com.mengma.test 包下创建一个名为 SecondEHChcheTest 的测试类,并在类中添加一个 testCache() 方法。在 testCache() 方法中,需要开启两个 Session 对象,然后使用 get() 方法查询四次,通过比较查询结果,观察二级缓存的使用情况。其实现代码如下所示。package com.mengma.test; import org.hibernate.Session; import org.hibernate.Transaction; import org.junit.Test; import com.mengma.domain.Person; import com.mengma.utils.HibernateUtils; public class SecondEHChcheTest { @Test public void testCache() { Session session1 = HibernateUtils.getSession(); // 开启第一个Session对象 Transaction tx1 = session1.beginTransaction(); // 开启第一个事务 Person p1 = (Person) session1.get(Person.class, 1); // 获取p1对象 Person p2 = (Person) session1.get(Person.class, 1); // 获取p2对象 System.out.println(p1 == p2); // 第一次比较 tx1.commit(); // 提交事务 session1.close(); // sesison1对象关闭,一级缓存被清理 Session session2 = HibernateUtils.getSession(); // 开启第二个Session对象 Transaction tx2 = session2.beginTransaction();// 开启第二个事务 Person p3 = (Person) session2.get(Person.class, 1); // 获取p3对象 System.out.println(p1 == p3); // 第二次比较 Person p4 = (Person) session2.get(Person.class, 1); // 获取p4对象 System.out.println(p3 == p4); // 第三次比较 tx2.commit(); // 提交事务2 session2.close(); // session2关闭 } }
5. 运行程序并查看结果
使用 JUnit 测试运行 testCache() 方法,运行成功后,控制台的输出结果如图 2 所示。图 2 testCache() 方法的测试结果
从图 2 中可以看到,控制台只输出了一个查询 SQL,这说明 Hibernate 只在数据库中查询了一次。而下面的 true、false 和 true 是三次比较输出的结果。详细解释具体如下。
1)在上述代码中,开启了两个 Session 和事务,从第一个 Session 中获取 p1 对象时,由于一级缓存和二级缓存中没有相应的数据,需要从数据库中查询,所以发出了 SQL 语句。
2)查询出 p1 对象后,p1 对象会保存到一级缓存和二级缓存中。当获取 p2 对象时,因为 Session 没有关闭,所以会从一级缓存中取出该对象。由于 p1 和 p2 对象都保存在一级缓存中,而且指向的是同一实体对象,所以第一次输出结果为true。
3)接着提交事务 tx1,并关闭 session1,此时一级缓存中的数据会被清除。
4)接下来开启第二个 Session 和事务,获取 p3 对象,此时控制台没有产生 SQL 语句是因为 p3 对象是从二级缓存中获取的。取出后,二级缓存会将数据同步到一级缓存中,这时 p3 对象又在一级缓存中存在了。
5)因为 p3 对象是从二级缓存中获取的,而二级缓存中存储的都是对象的散装数据,它们会重新 new 出一个新的对象,所以第二次输出的结果为 false。
6)最后获取 p4 对象时,由于一级缓存中已经存在了 Person 对象,Hibernate 会直接从一级缓存中获取,所以输出结果为 true。