JPA(EclipseLink)单元测试逻辑删除后查询未生效,如何强制重查?
解决Spring Data JPA(EclipseLink)逻辑删除后findOne仍返回实体的问题
你遇到的这个问题核心原因是**EclipseLink的一级缓存(持久化上下文)**在搞鬼:第一次调用findOne时,实体已经被加载到内存缓存中,后续执行逻辑删除(设置removed=1并save)后,缓存里的实体并没有被自动更新或移除,所以第二次findOne直接从缓存返回了旧对象,而没有去数据库重新查询——这就导致你的@AdditionalCriteria("this.removed = 0")注解在这次缓存命中时没有生效。
下面给你几个可行的解决方案,按测试场景的实用性排序:
1. 清除持久化上下文缓存(最适合单元测试)
直接清空当前持久化上下文的所有缓存实体,这样第二次findOne就必须去数据库查询,自然会被@AdditionalCriteria过滤。
步骤:
- 在测试类中注入
EntityManager - 执行逻辑删除后,调用
em.clear()清除缓存
修改后的测试代码:
@RunWith(SpringJUnit4ClassRunner.class) @TestExecutionListeners({ DependencyInjectionTestExecutionListener.class, TransactionalTestExecutionListener.class, WithSecurityContextTestExecutionListener.class }) @ContextConfiguration(locations = {"file:src/test/resources/applicationContext-test.xml"}) public class RepositoryTest { @Autowired private MyRepository repository; @PersistenceContext private EntityManager em; // 注入EntityManager @Test // 注意:你的测试方法缺少@Test注解,必须加上才能执行 @WithUserDetails(value = "user") public void testDeleteEvent() { Object event = repository.findOne(123); repository.delete(123); // 清除持久化上下文缓存,强制后续查询走数据库 em.clear(); event = repository.findOne(123); assertTrue(event == null); } }
2. 自定义Repository方法,添加强制刷新的查询提示
在你的MyRepository中定义一个带查询提示的方法,强制EclipseLink绕过缓存查询数据库:
public interface MyRepository extends JpaRepository<YourEntity, Long> { @QueryHints({ @QueryHint(name = org.eclipse.persistence.config.QueryHints.REFRESH, value = "true") }) YourEntity findOneWithRefresh(Long id); }
然后在测试中调用这个方法:
event = repository.findOneWithRefresh(123);
3. 使用EntityManager的find方法指定刷新模式
直接通过EntityManager的find方法,并传入FORCE_REFRESH的刷新模式,强制从数据库加载:
event = em.find(YourEntity.class, 123, RefreshModeType.FORCE_REFRESH);
补充说明
- 别忘了给测试方法加上
@Test注解,否则测试不会被执行(你的代码里漏掉了这个) @AdditionalCriteria是在生成JPQL查询时生效的,只会影响从数据库查询的结果,不会自动清理缓存中的实体,所以必须通过上述方式强制绕过缓存。
内容的提问来源于stack exchange,提问作者Toozzii
相关产品推荐
相关产品推荐

