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

升级到Java17+Spring Boot2.5.5后单元测试@Sql执行脚本异常如何解决?

解决方案

根因确认

你定位的问题完全正确:Spring Boot 2.5.x版本升级后,默认会对Hikari数据源生成AOP代理对象,而JpaTransactionManager和@Sql注解逻辑拿到的是两个不同的代理实例,代理类未正确重写equals方法导致比较失败,触发校验异常。

可落地修复方案

  • 方案1:修改@Sql注解配置(最快修复,无侵入)
    给@Sql注解显式指定独立事务模式,跳过数据源和事务管理器的绑定校验:
    @Sql(scripts = "/clear_data.sql", 
         executionPhase = ExecutionPhase.AFTER_TEST_METHOD,
         transactionMode = Sql.TransactionMode.ISOLATED)
    
    该模式下@Sql会单独申请数据库连接执行脚本,不依赖测试方法的事务上下文,不会触发数据源一致性校验。
  • 方案2:关闭测试环境数据源代理
    在测试环境的application-test.properties配置文件中添加配置,关闭数据源自动代理:
    spring.datasource.hikari.allow-pool-suspension=false
    # 若全局开启了AOP自动代理可追加以下配置,仅测试环境生效
    spring.aop.auto=false
    
    关闭代理后事务管理器和@Sql逻辑拿到的都是原始Hikari数据源实例,equals比较正常。
  • 方案3:升级Spring Boot版本(官方修复)
    该问题属于Spring Framework 5.3.x早期版本的已知bug,官方在后续版本优化了代理对象的比较逻辑,你可以选择将Spring Boot版本升级到2.5.15及以上,或者2.6.x/2.7.x稳定版本,升级后无需修改业务代码即可解决问题。
  • 方案4:自定义测试监听器(特殊场景使用)
    如果前三种方案都不符合你的业务要求,可以重写Sql执行的校验逻辑,解代理后再比较数据源:
    public class CustomSqlScriptsTestExecutionListener extends SqlScriptsTestExecutionListener {
        @Override
        protected boolean sameDataSource(DataSource ds1, DataSource ds2) {
            if (ds1 == ds2) {
                return true;
            }
            // 解开代理获取真实数据源对象
            Object realDs1 = AopProxyUtils.getSingletonTarget(ds1);
            Object realDs2 = AopProxyUtils.getSingletonTarget(ds2);
            realDs1 = realDs1 == null ? ds1 : realDs1;
            realDs2 = realDs2 == null ? ds2 : realDs2;
            return realDs1.equals(realDs2);
        }
    }
    
    然后在测试类上替换默认的Sql执行监听器即可:
    @TestExecutionListeners(
        value = CustomSqlScriptsTestExecutionListener.class,
        mergeMode = TestExecutionListeners.MergeMode.MERGE_WITH_DEFAULTS
    )
    

内容的提问来源于stack exchange,提问作者KnockKnock

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.25 17:15:03