Spring Boot中H2数据库@Transactional方法回滚失效求助
Spring Boot事务测试失败的解决建议
问题核心
你当前的测试代码手动创建了Service实例,导致@Transactional注解完全不生效。Spring的事务是通过AOP代理实现的,只有Spring容器管理的Bean(而非手动new的对象)才会被织入事务逻辑,所以A表的删除操作无法回滚。
解决方案步骤
1. 让Spring管理Service和Repository实例
测试类要启用Spring上下文,通过@Autowired注入Service,用@MockBean替换需要模拟的BRepository,不要手动new对象。
2. 修改测试代码示例
@SpringBootTest @Transactional // 可选:测试结束自动回滚上下文,避免污染测试环境 class ServiceTest { @Autowired private Service service; @Autowired private JdbcTemplate jdbcTemplate; // 用@MockBean替换Spring容器中的BRepository实例 @MockBean private BRepository mockBRepository; @Test void testDeleteRowsRollback() { // 初始化测试数据:TABLE_A插入1条数据 jdbcTemplate.update("INSERT INTO TABLE_A (id) VALUES (123)"); assertTableHasRows(1, "TABLE_A"); // 模拟BRepository的deleteRow方法抛出RuntimeException doThrow(RuntimeException.class) .when(mockBRepository) .deleteRow(123); // 执行方法并断言异常抛出 assertThrows(RuntimeException.class, service::deleteRows); // 验证TABLE_A的数据未被删除(事务回滚) assertTableHasRows(1, "TABLE_A"); } private void assertTableHasRows(int expectedCount, String tableName) { Integer actualCount = jdbcTemplate.queryForObject("SELECT COUNT(*) FROM " + tableName, Integer.class); assertEquals(expectedCount, actualCount); } }
3. 确认Service类的Spring注解
确保你的Service类被@Service(或@Component)标记,这样Spring才能扫描并将其纳入容器管理:
@Service public class Service { private final ARepository aRepository; private final BRepository bRepository; // 构造函数注入(推荐) public Service(ARepository aRepository, BRepository bRepository) { this.aRepository = aRepository; this.bRepository = bRepository; } @Transactional public void deleteRows() { aRepository.deleteRow(123); bRepository.deleteRow(123); } }
关键注意事项
@Transactional仅对Spring容器管理的Bean的公共方法生效,手动new的对象不会触发事务代理。- 默认情况下,Spring事务只会在抛出
RuntimeException(或其子类)时回滚,你的代码中抛出的是RuntimeException,符合回滚条件。 - 测试类中的
@Transactional会在测试结束后自动回滚所有操作,避免测试数据污染后续用例。
内容的提问来源于stack exchange,提问作者user2042190
相关产品推荐
相关产品推荐

