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

Spring:如何在测试方法的事务中执行@Sql注解?

解决Spring Boot测试中@Sql与事务共享的问题

你的问题核心在于默认的@Sql注解会创建独立事务执行脚本,和测试方法的事务完全分开,所以脚本执行后的修改要么提交(但测试方法的事务因隔离级别看不到)要么回滚,导致测试拿不到预期的数据。要实现你想要的「同一个事务内先执行准备SQL,再跑测试,最后一起回滚」的逻辑,有两种可靠的方案:

方案一:配置@Sql复用测试方法的事务

通过@SqlConfig注解指定transactionMode为INFERRED,让@Sql不再单独开事务,而是复用测试方法由@Transactional开启的事务。这样准备SQL和测试逻辑就处在同一个事务上下文里,最后统一回滚。

代码示例:

@SpringBootTest
@Transactional
@Rollback(true)
public class YourTestClass {

    @Test
    @Sql(scripts = "/path/to/your/setup.sql", config = @SqlConfig(transactionMode = SqlConfig.TransactionMode.INFERRED))
    public void yourTestMethod() {
        // 这里可以正常读取setup.sql修改的数据
        // 执行你的测试逻辑
    }
}

简单解释:

  • TransactionMode.INFERRED表示@Sql会自动检测当前是否存在活跃事务(也就是测试方法的@Transactional开启的事务),如果存在就直接复用,不会新建独立事务。
  • 整个流程就完全符合你的需求:测试方法启动 → 开启事务 → 执行准备SQL → 处理测试逻辑 → 事务回滚。

方案二:手动在测试方法内执行SQL脚本

如果觉得注解配置不够直观,也可以在测试方法开头手动调用工具类执行SQL脚本,这样脚本的执行必然和测试方法处于同一个事务中。

代码示例:

@SpringBootTest
@Transactional
@Rollback(true)
public class YourTestClass {

    @Autowired
    private DataSource dataSource;

    @Test
    public void yourTestMethod() throws Exception {
        // 手动执行准备SQL脚本
        ScriptUtils.executeSqlScript(dataSource.getConnection(), new ClassPathResource("/path/to/your/setup.sql"));
        
        // 执行测试逻辑,能正常读取脚本修改的数据
    }
}

注意:这里不需要手动关闭连接,测试方法的事务会全程管理这个连接,最后统一回滚所有操作。

为什么原来的@Sql无效?

默认情况下,@Sql的transactionMode是ISOLATED,它的执行流程是:

  1. 开启一个独立的新事务
  2. 执行指定的SQL脚本
  3. 默认提交这个事务(除非额外配置了回滚)
    但测试方法的事务是后续才开启的,根据数据库默认的事务隔离级别(比如READ COMMITTED),测试方法的事务看不到之前已提交的修改;如果你的环境中@Sql的事务被意外回滚(比如继承了类上的@Rollback配置),那测试方法就更看不到任何数据变更了。

所以只要让@Sql复用测试方法的事务,就能完美解决这个问题。

内容的提问来源于stack exchange,提问作者fedor.belov

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.25 03:33:00