@ExpectedDatabase未按预期工作:JUnit测试异常原因排查
问题:JUnit删除操作测试失败,取消注释查询语句后才通过(EclipseLink JPA)
我编写了一个JUnit测试用于校验仓储层的数据库删除操作,使用@DatabaseSetup初始化数据库,@ExpectedDatabase验证删除后的数据库状态。测试代码如下:
@Test @ExpectedDatabase( table = "OBJECT_ALIAS", value = "classpath:dbunit/data/object_alias_deleted_2115_ALIAS_5.xml") public void testDeleteObjectAlias() { ObjectAlias objectAlias = new ObjectAlias(2115, 5, "NewAlias"); objectAliasRepository.deleteObjectAlias(objectAlias); //objectAliasRepository.findByPartyNo(5); //取消注释后测试通过 }
当前测试执行失败,但取消注释上述查询语句后测试即可通过。我使用EclipseLink作为JPA提供者,请问导致该现象的原因是什么?
原因分析
核心问题出在JPA的一级缓存(EntityManager缓存)和操作延迟同步机制上,具体细节:
- EclipseLink默认采用延迟同步策略:调用
deleteObjectAlias后,删除操作仅被存入EntityManager的待执行队列,并未立即执行数据库层面的DELETE语句。 @ExpectedDatabase直接查询数据库验证状态:此时数据库中的目标记录还未被删除,验证自然不通过。- 查询触发缓存刷新(flush):取消注释
findByPartyNo(5)后,JPA会在执行查询前自动触发flush,将EntityManager中待执行的删除操作同步到数据库。DELETE语句真正执行后,数据库记录被删除,@ExpectedDatabase的验证就符合预期了。
另外补充事务边界的影响:如果测试方法默认开启事务,事务会在方法结束时才提交,而@ExpectedDatabase的验证是在事务提交前执行的。查询触发的flush相当于提前同步操作,让验证能获取到数据库的最新状态。
内容的提问来源于stack exchange,提问作者Darshil Shah
相关产品推荐
相关产品推荐

