Administrator
发布于 2026-04-29 / 11 阅读
0
0

事务失效

Spring多数据源事务失效复盘:@Transactional 异常无法回滚

一、问题现象

项目存在两套独立数据源,全局公共数据源、业务自定义数据源。

  1. 业务方法添加@Transactional并指定自定义事务管理器,接口无任何报错。
  2. 代码主动抛出异常,数据库插入数据无法回滚。

二、相关业务配置代码

1. 全局数据源配置类

@Configuration
@MapperScan(basePackages = "com.**.mapper", sqlSessionTemplateRef = "sSqlSessionTemplate")
public class DruidConfiguration {
    @Bean(name = "BData")
    public DataSource BData() {
        return new DruidDataSource();
    }
}

2. 业务自定义数据源配置类

@Configuration
public class CustomDataSourceConfig {
    @Bean("mDataSource")
    public DataSource mDataSource(){
        return new DruidDataSource();
    }

    @Bean("mDataSourceTransactionManager")
    public PlatformTransactionManager mTransactionManager(){
        return new DataSourceTransactionManager(mDataSource());
    }
}

3. 事务失效业务代码

@Transactional(rollbackFor = Exception.class, transactionManager = "mDataSourceTransactionManager")
public void batchInsert() {
    for (int i = 0; i < 50; i++) {
        bizMapper.insert(data);
    }
    throw new RuntimeException("测试事务回滚");
}

三、两种简单排查方式

方式一 数据库自测 无需写代码

  1. 在自定义业务库新建一张独有测试表,全局公共库不创建该表
  2. 调用Mapper执行该表插入SQL
  3. 抛出表不存在异常,说明Mapper使用全局数据源;能正常插入,说明使用自定义数据源

方式二 Debug断点查看

打断点在Mapper调用处,直接逐层查看绑定链路,直观看到当前Mapper使用的数据源

Mapper代理对象 -> MapperProxy -> sqlSession -> SqlSessionFactory -> Configuration -> Environment -> dataSource

四、客观问题事实

  1. 项目存在两个@MapperScan,扫描范围存在重叠
  2. 当前业务Mapper实际绑定全局公共数据源
  3. 事务绑定自定义数据源,和Mapper执行SQL的数据源不一致
  4. 两个数据源相互独立,导致事务无法回滚数据库操作

五、问题难以排查的原因

  1. 手动指定事务管理器,规避了多事务管理器冲突报错,无显性错误提示
  2. 两套数据源业务表名、结构完全一致,不会出现表不存在的SQL异常
  3. 全程无报错,仅存在事务不回滚的隐性业务问题

六、解决方案

有效方案

修改业务Mapper文件夹名称,脱离全局通配扫描范围
单独为业务Mapper配置专属@MapperScan,绑定自定义数据源相关配置,事务即可正常回滚

无效方案

在同路径下新增精准路径@MapperScan,无法改变已绑定的数据源关系,解决不了问题

七、开发总结

  1. 多数据源项目,不使用com.**.mapper全局通配扫描Mapper
  2. 事务无报错但无法回滚,优先核查Mapper实际使用的数据源
  3. 多数据源场景,物理隔离Mapper目录是最稳妥的方式

评论