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

Spring Data JPA @DataJpaTest测试问题:一级缓存致字段断言不符

你说得没错,问题核心确实是JPA的一级缓存(EntityManager缓存):执行saveAndFlush后,实体实例会被缓存起来,后续的findById直接读取缓存中的对象,导致name字段还是构造时的"John Doe",而非数据库里的真实值(null)。

下面是两种正确编写测试用例的方法:

方法1:清空一级缓存,强制从数据库查询

注入EntityManager,在保存操作后调用clear()清空缓存,让后续查询重新从数据库加载实体:

@DataJpaTest(showSql = true)
class TestUserRepository
{
    @Autowired
    private UserRepository repository;
    
    @Autowired
    private EntityManager entityManager;

    @Test
    public void testCreateUser()
    {
        repository.saveAndFlush(new User(101, "John Doe"));
        
        // 清空当前EntityManager的一级缓存
        entityManager.clear();

        final var optional = repository.findById(101L);
        assertTrue(optional.isPresent());

        var user = optional.get();
        assertNull(user.getName());
    }
}

方法2:刷新实体,同步数据库状态

如果不想清空所有缓存,也可以直接刷新已保存的实体,将数据库的最新状态同步到缓存对象:

@DataJpaTest(showSql = true)
class TestUserRepository
{
    @Autowired
    private UserRepository repository;
    
    @Autowired
    private EntityManager entityManager;

    @Test
    public void testCreateUser()
    {
        var savedUser = repository.saveAndFlush(new User(101, "John Doe"));
        
        // 从数据库同步该实体的最新状态
        entityManager.refresh(savedUser);

        assertNull(savedUser.getName());
    }
}

补充说明

  • @Column(insertable = false)会让JPA生成INSERT语句时忽略name字段,因此数据库中该字段会以默认值(这里是null)存储。
  • 一级缓存与当前EntityManager绑定,生命周期跟随事务:clear()会清空缓存中所有实体,refresh()仅针对单个实体同步数据库状态,可根据测试场景选择。

内容的提问来源于stack exchange,提问作者SetNug

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 23:42:31