Hibernate整合EHCache实现二级缓存

在《 Hibernate二级缓存的并发访问策略和常用插件》教程介绍的几种常用的二级缓存插件中,EHCache 缓存插件是理想的进程范围的缓存插件。本小节将以 EHCache 缓存插件为例,介绍二级缓存的配置和使用。本节在教程前几节实例的基础上进行整合,具体步骤如下:

1. 引入 EHCache 相关的 JAR 包

读者可以从官方网址 http://www.ehcache.org/downloads/ 中下载 EHCache 的 JAR 包,成功访问后的页面显示如图 1 所示。
 

EHCache的下载


图 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 所示。
 

testCache()方法的测试结果


图 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。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
好的,下面是Spring Boot整合Ehcache解决Mybatis二级缓存数据脏读的详细步骤: 1. 添加依赖 首先,需要在pom.xml文件中添加Ehcache和Spring Boot的相关依赖: ``` <!-- Ehcache依赖 --> <dependency> <groupId>net.sf.ehcache</groupId> <artifactId>ehcache</artifactId> <version>2.10.6</version> </dependency> <!-- Spring Boot依赖 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>2.1.3</version> </dependency> ``` 2. 配置Ehcache 在src/main/resources目录下创建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"> <!-- 默认缓存配置 --> <defaultCache maxEntriesLocalHeap="10000" eternal="false" timeToIdleSeconds="120" timeToLiveSeconds="120" diskSpoolBufferSizeMB="30" maxEntriesLocalDisk="10000000" diskExpiryThreadIntervalSeconds="120" memoryStoreEvictionPolicy="LRU" statistics="true"> </defaultCache> <!-- Mybatis二级缓存配置 --> <cache name="com.example.demo.mapper.UserMapper" maxEntriesLocalHeap="10000" eternal="false" timeToIdleSeconds="120" timeToLiveSeconds="120" diskSpoolBufferSizeMB="30" maxEntriesLocalDisk="10000000" diskExpiryThreadIntervalSeconds="120" memoryStoreEvictionPolicy="LRU" statistics="true"> </cache> </ehcache> ``` 在配置文件中,我们定义了默认缓存配置和针对UserMapper的缓存配置。 3. 配置Mybatis 在application.properties中添加Mybatis相关配置: ``` # Mybatis配置 mybatis.type-aliases-package=com.example.demo.entity mybatis.mapper-locations=classpath:mapper/*.xml mybatis.configuration.cache-enabled=true mybatis.configuration.local-cache-scope=session mybatis.configuration.cache-ref=ehcache ``` 注意,cache-enabled属性设置为true,local-cache-scope属性设置为session,并指定了使用的缓存提供者为Ehcache。 4. 配置缓存管理器 在启动类中配置缓存管理器: ``` @Configuration @EnableCaching public class CacheConfig { @Bean public CacheManager cacheManager() { EhCacheCacheManager cacheManager = new EhCacheCacheManager(); cacheManager.setCacheManager(ehCacheManagerFactoryBean().getObject()); return cacheManager; } @Bean public EhCacheManagerFactoryBean ehCacheManagerFactoryBean() { EhCacheManagerFactoryBean cacheManagerFactoryBean = new EhCacheManagerFactoryBean(); cacheManagerFactoryBean.setConfigLocation(new ClassPathResource("ehcache.xml")); cacheManagerFactoryBean.setShared(true); return cacheManagerFactoryBean; } } ``` 在这里,我们通过EhCacheCacheManager和EhCacheManagerFactoryBean来配置缓存管理器。 5. 开启缓存 最后,在Mapper接口中开启缓存: ``` @CacheNamespace(implementation = net.sf.ehcache.Cache.class, eviction = FifoPolicy.class) public interface UserMapper { @Select("SELECT * FROM user WHERE id = #{id}") @Options(useCache = true, flushCache = Options.FlushCachePolicy.FALSE, timeout = 10000) User selectById(Integer id); @Update("UPDATE user SET name = #{name} WHERE id = #{id}") void updateNameById(@Param("id") Integer id, @Param("name") String name); } ``` 使用@CacheNamespace注解来指定缓存实现类和缓存策略,在每个查询方法上使用@Options注解来开启缓存。 至此,Spring Boot整合Ehcache解决Mybatis二级缓存数据脏读的配置就完成了。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

智慧浩海

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值