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,它的执行流程是:
- 开启一个独立的新事务
- 执行指定的SQL脚本
- 默认提交这个事务(除非额外配置了回滚)
但测试方法的事务是后续才开启的,根据数据库默认的事务隔离级别(比如READ COMMITTED),测试方法的事务看不到之前已提交的修改;如果你的环境中@Sql的事务被意外回滚(比如继承了类上的@Rollback配置),那测试方法就更看不到任何数据变更了。
所以只要让@Sql复用测试方法的事务,就能完美解决这个问题。
内容的提问来源于stack exchange,提问作者fedor.belov
相关产品推荐
相关产品推荐

