升级Hibernate 5后EhCache配置失效:JCache相关技术咨询
我来逐个拆解你的三个问题,结合Hibernate 5和Ehcache 3的实际情况给你说明:
问题1:能否在Hibernate 5 + Ehcache 3环境下继续使用SingletonEhCacheRegionFactory?
答案是不行,核心原因有两点:
SingletonEhCacheRegionFactory是Hibernate专门为Ehcache 2.x开发的集成类,它依赖的是Ehcache 2的内部API以及旧版Hibernate缓存SPI(比如你报错里的org.hibernate.cache.TimestampsRegion,这个类在Hibernate 5的缓存SPI重构后已经被移除/重命名)。- 你当前引入的是Ehcache 3.x,它的API和架构完全重构,不再兼容Ehcache 2的生态,哪怕这个类没被标记为过时,也无法和Ehcache 3配合工作。
如果非要沿用类似旧版的Ehcache集成逻辑,你得换回Ehcache 2.x版本,同时确保hibernate-ehcache依赖版本和Hibernate核心版本匹配,但显然这不推荐——Ehcache 2早已停止维护,存在安全风险。
问题2:新的JCache是什么?它仅用于方法返回值缓存吗?
JCache(JSR-107)是Java官方制定的标准化缓存API规范,它定义了一套通用的缓存操作接口,让不同缓存实现(比如Ehcache 3、Caffeine、Redis等)可以统一接入,不用关心具体实现细节。
它绝对不是只用于方法缓存:
- Hibernate的二级缓存(实体缓存):可以通过JCache作为缓存提供者,把实体数据缓存到Ehcache 3中,和你之前用Ehcache 2的二级缓存功能完全一致。
- Hibernate的查询缓存:同样可以通过JCache实现,Hibernate会把查询结果集缓存到JCache指定的区域里。
- 方法缓存(比如Spring的
@Cacheable)只是JCache的一个应用场景,它的核心价值是提供通用缓存能力,支持各种缓存需求。
问题3:如何将旧的EhCache配置转换为新版本?
Ehcache 3的配置格式和Ehcache 2差异极大,你遇到的SAX解析错误就是因为旧配置的根元素<ehcache>不符合Ehcache 3的XML schema。下面是把你的旧配置转换成Ehcache 3格式的完整示例:
第一步:编写新的Ehcache 3配置文件(比如命名为ehcache3.xml)
<?xml version="1.0" encoding="UTF-8"?> <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="https://www.ehcache.org/v3 https://www.ehcache.org/schema/ehcache-core-3.0.xsd" xmlns="https://www.ehcache.org/v3"> <!-- 对应旧版diskStore,设置磁盘存储路径 --> <persistence directory="${java.io.tmpdir}/ehcache"/> <!-- 对应旧版defaultCache,作为所有缓存的默认模板 --> <defaults> <expiry> <tti>300</tti> <!-- 对应timeToIdleSeconds: 300秒 --> <ttl>600</ttl> <!-- 对应timeToLiveSeconds: 600秒 --> </expiry> <heap unit="entries">10000</heap> <!-- 对应maxElementsInMemory: 10000 --> <offheap unit="MB">30</offheap> <!-- 对应diskSpoolBufferSizeMB: 30MB,用堆外存储替代更合理 --> <disk persistent="true" unit="entries">10000</disk> <!-- 对应maxElementsOnDisk: 10000 --> <eviction-policy>LRU</eviction-policy> <!-- 对应memoryStoreEvictionPolicy: LRU --> </defaults> <!-- Hibernate更新时间戳缓存 --> <cache alias="org.hibernate.cache.spi.UpdateTimestampsCache"> <heap unit="entries">10000</heap> <expiry> <none/> <!-- 对应旧版eternal="false"但未设置过期时间,这里表示永不过期 --> </expiry> </cache> <!-- Hibernate标准查询缓存 --> <cache alias="org.hibernate.cache.internal.StandardQueryCache"> <heap unit="entries">10000</heap> <expiry> <ttl>300</ttl> <!-- 对应timeToLiveSeconds: 300秒 --> </expiry> </cache> <!-- 自定义实体缓存:br.com.atlantico.toi.model.calc.Anomalia --> <cache alias="br.com.atlantico.toi.model.calc.Anomalia"> <heap unit="entries">10000</heap> <expiry> <tti>300</tti> <ttl>600</ttl> </expiry> </cache> </config>
第二步:调整Hibernate的JCache配置
先移除hibernate-ehcache依赖(它是Ehcache 2的整合包,和Ehcache 3冲突),保留hibernate-jcache、ehcache及其他Hibernate核心依赖。然后修改Hibernate的properties配置:
// 开启二级缓存和查询缓存 properties.put(Environment.USE_SECOND_LEVEL_CACHE, "true"); properties.put(Environment.USE_QUERY_CACHE, "true"); // 指定JCache缓存区域工厂 properties.put(Environment.CACHE_REGION_FACTORY, JCacheRegionFactory.class.getName()); // 指定Ehcache 3作为JCache提供者 properties.put("hibernate.javax.cache.provider", org.ehcache.jsr107.EhcacheCachingProvider.class.getName()); // 指向新的Ehcache 3配置文件 properties.put("hibernate.javax.cache.uri", "App/config/ehcache3.xml");
额外说明:
- Ehcache 3支持堆内、堆外、磁盘多层缓存,你可以根据业务需求调整存储层级和参数。
- 除了XML配置,也可以用Java代码方式配置Ehcache 3,再通过Hibernate的JCache集成接入。
内容的提问来源于stack exchange,提问作者mjs




