Hibernate二级Ehcache缓存配置异常:不可写入问题咨询
核心结论
你看到的日志不是单纯的警告,你的Hibernate二级缓存已经完全无法正常工作:缓存命中但数据不可读,查询不得不走数据库;尝试写入缓存也失败,导致后续查询也无法复用缓存。
根本原因
1. 缓存区域名不匹配
Hibernate默认使用实体的全限定类名作为二级缓存区域名(比如br.com.example.Post),但你在ehcache.xml中配置的缓存别名是cachePost/cachePostComment,两者完全不匹配。虽然你设置了hibernate.javax.cache.missing_cache_strategy=create,Hibernate会自动创建缺失的缓存区域,但自动创建的缓存没有适配READ_WRITE并发策略的事务性配置,导致缓存读写的事务校验失败。
2. 缓存Key类型配置错误
你在ehcache.xml中把缓存Key类型设为java.lang.Long,但Hibernate二级缓存的实际Key是复合标识符(格式为实体类名#ID,比如br.com.example.Post#1),类型为Serializable,而非单纯的ID值。Key类型不匹配会导致缓存无法正确存储和读取数据,进一步触发事务校验失败。
修复方案
方案一:匹配默认缓存区域名
修改ehcache.xml,将缓存别名改为实体的全限定类名,并修正Key类型:
<ehcache:cache-template name="myDefaultTemplate"> <ehcache:expiry> <ehcache:none/> </ehcache:expiry> </ehcache:cache-template> <ehcache:cache alias="br.com.example.Post" uses-template="myDefaultTemplate"> <ehcache:key-type>java.io.Serializable</ehcache:key-type> <ehcache:value-type>br.com.example.Post</ehcache:value-type> <ehcache:heap unit="entries">200</ehcache:heap> </ehcache:cache> <ehcache:cache alias="br.com.example.PostComment" uses-template="myDefaultTemplate"> <ehcache:key-type>java.io.Serializable</ehcache:key-type> <ehcache:value-type>br.com.example.PostComment</ehcache:value-type> <ehcache:heap unit="entries">200</ehcache:heap> </ehcache:cache>
方案二:自定义缓存区域名(需关联实体)
如果你想保留cachePost这类自定义别名,需要在实体的@Cache注解中指定region属性,同时修正Key类型:
@Entity @Cache(usage = CacheConcurrencyStrategy.READ_WRITE, region = "cachePost") public class Post implements Serializable { // ... 实体代码 } @Entity @Cache(usage = CacheConcurrencyStrategy.READ_WRITE, region = "cachePostComment") public class PostComment implements Serializable { // ... 实体代码 }
对应的ehcache.xml中保持别名不变,但修正Key类型为java.io.Serializable。
额外优化:测试时脱离原事务上下文
你的测试代码中,entityManager.clear()仅清空一级缓存,但当前EntityManager的事务上下文仍会影响二级缓存的读写校验。建议关闭原EntityManager后重新打开,确保完全脱离之前的事务:
public static void main(String[] args) { EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory("test-pu"); EntityManager entityManager = entityManagerFactory.createEntityManager(); // 持久化数据 Post post = new Post(); entityManager.getTransaction().begin(); post.setAuthor("Author"); entityManager.persist(post); entityManager.getTransaction().commit(); // 关闭原EntityManager,脱离事务上下文 entityManager.close(); // 新EntityManager查询,验证二级缓存 EntityManager newEntityManager = entityManagerFactory.createEntityManager(); logger.info("1st level cache cleared (new EntityManager)"); Post cachedPost = newEntityManager.find(Post.class, post.getId()); logger.info("Post: {}", cachedPost); newEntityManager.close(); entityManagerFactory.close(); }
验证修复效果
修复后重新运行,日志中应该看不到Cache hit, but item is unreadable/invalid和Cache put-from-load failed的信息,且第二次查询不会触发SQL语句(即直接从二级缓存读取)。
内容的提问来源于stack exchange,提问作者Eduardo Bortolatto Lopes

