You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.06 07:39:49