You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.25 10:57:33