Spring Boot 2中@DataJpaTest事务无法回滚的问题咨询
这个问题我之前也碰到过,大概率是你的注解组合和扫描配置冲突了,咱们一步步来排查解决:
1. 先理清@DataJpaTest的默认特性
@DataJpaTest本身已经默认自带了@Transactional和@Rollback(true),你手动添加的这两个注解其实是重复的,虽然不会直接导致回滚失效,但完全没必要保留,可以先去掉。
2. 问题核心:@ComponentScan破坏了切片测试的隔离性
@DataJpaTest是Spring提供的切片测试注解,它的设计初衷是只加载JPA相关组件(比如@Entity、Repository、EntityManager等),避免加载整个应用上下文,既提升测试效率又减少外部干扰。
但你添加的@ComponentScan(basePackages = "com.acma")会强制扫描整个com.acma包下的所有Bean,包括各种@Configuration、@Service等,这很可能引入了自定义的事务配置(比如自定义的PlatformTransactionManager)或者其他影响Spring Test事务机制的Bean,直接冲掉了@DataJpaTest默认的回滚逻辑。
3. 修复方案
步骤一:清理冗余注解和扫描配置
先把不必要的注解去掉,修改后的测试类如下:
@RunWith(SpringRunner.class) @DataJpaTest @AutoConfigureTestDatabase(replace = Replace.NONE) public class FooTest { @Autowired private EntityManager em; @Autowired private JdbcTemplate jdbcTemplate; @Test public void persist() throws Exception { em.persist(new Foo()); em.flush(); // 强制刷新到数据库,方便验证事务状态 // 测试方法内处于事务中,能看到插入的数据 Long count = jdbcTemplate.queryForObject("SELECT COUNT(*) FROM foo", Long.class); assert count == 1; } @After public void verifyRollback() { // 事务结束后自动回滚,数据库里应该没有数据 Long count = jdbcTemplate.queryForObject("SELECT COUNT(*) FROM foo", Long.class); assert count == 0; } }
步骤二:按需加载Bean,用@Import代替全量扫描
如果测试时确实需要加载com.acma包下的某个特定Bean(比如自定义的Repository配置),不要用全量的@ComponentScan,而是用@Import(YourRequiredBean.class)来精准加载,避免引入无关配置干扰事务逻辑。
步骤三:检查自定义事务配置
如果项目里有自定义的事务配置类(比如标注了@EnableTransactionManagement的类),要确保它在测试环境下不会覆盖@DataJpaTest默认的事务管理器。可以给配置类加上@Profile("!test"),让它在测试环境下不生效,或者在测试类里显式指定正确的事务管理器。
4. 验证回滚是否生效
可以像上面的代码那样,在@After方法里查询数据库,确认事务结束后数据被回滚。也可以在测试结束后直接连接数据库查看foo表的数据,正常情况下应该是空的。
内容的提问来源于stack exchange,提问作者Chico Sokol

