java单元测试中验证事务回滚,需在@transactional测试中抛出runtimeexception触发自动回滚,并用jdbctemplate查询断言数据未写入;或用testtransaction.flagforrollback()手动控制回滚;须避免this调用、异常捕获不重抛、上下文未加载等陷阱。

Java 单元测试中对带事务的方法做回滚测试,关键不是“手动触发回滚”,而是构造一个能真实触发 Spring 事务回滚机制的场景,并验证数据确实未落库。核心是让测试运行在事务中,再通过抛出异常或显式标记来激活回滚行为。
用 @Transactional + @Rollback 配合异常触发回滚
这是最直接、最贴近生产逻辑的方式。Spring 默认对未捕获的运行时异常(RuntimeException 及其子类)自动回滚事务。
- 测试类或方法加
@Transactional,确保整个测试在事务上下文中执行 - 不加
@Rollback(false),保持默认回滚语义(即@Rollback(true)) - 在测试方法中调用目标服务方法后,主动抛出一个运行时异常(如
throw new RuntimeException("simulate failure")) - 用
JdbcTemplate或 Repository 查询数据库,断言记录数为 0 或原始值未变
用 TestTransaction 手动控制回滚流程
当需要更细粒度控制事务生命周期(比如想在中间检查状态、再决定是否回滚),可用 Spring 提供的 TestTransaction 工具类:
- 调用
TestTransaction.flagForRollback()显式标记当前事务需回滚 - 执行业务逻辑(如保存数据)
- 调用
TestTransaction.end()结束事务,此时回滚生效 - 后续查询可验证数据未写入——这种方式不依赖异常,更适合验证“条件性回滚”逻辑
验证回滚是否真正生效的实操要点
光有注解不够,必须通过查询确认结果。常见误区是只断言异常抛出,却没查库。
- 使用
JdbcTemplate.queryForObject("SELECT COUNT(*) FROM user", Integer.class)比单纯 try-catch 更可靠 - 若测试前有初始数据,建议先查基线值(如原记录数 = 5),执行后仍为 5 才算回滚成功
- 避免用 H2 的
create-drop策略做回滚验证——它每次重建表,掩盖了事务回滚行为;应改用validate或update模式
注意事务不生效的典型陷阱
回滚失败往往不是配置问题,而是调用方式或异常类型不对:
- 服务方法被本类其他方法直接调用(this.method()),绕过代理,事务失效
- catch 了异常但没重新 throw,或只 throw 了
Exception(checked 异常),而没设rollbackFor = Exception.class - 测试类没加载 Spring 上下文(漏了
@SpringBootTest或@ContextConfiguration),@Transactional形同虚设
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











