mybatis 多数据源与事务协同需依赖 spring 配置:通过 abstractroutingdatasource 动态路由数据源,为每个 datasource 配置独立的 datasourcetransactionmanager,跨库事务需引入 atomikos 等 jta 框架,mapper 须按数据源隔离 sqlsessionfactory 和扫描路径。

MyBatis 本身不直接管理数据源或事务,它依赖 Spring 的 DataSource 和 PlatformTransactionManager。真正实现多数据源和事务协同,关键在 Spring 配置层——尤其是如何让不同数据源被正确识别、路由,并让跨库操作具备事务一致性。
多数据源配置:用 AbstractRoutingDataSource 动态路由
Spring 提供 AbstractRoutingDataSource 作为多数据源核心载体,它通过重写 determineCurrentLookupKey() 方法,根据上下文(如线程变量)返回数据源标识(如 "master" 或 "slave"),再从预设的 targetDataSources Map 中取出对应 DataSource。
- 定义两个独立的 DataSource Bean(如 dataSourceMaster、dataSourceSlave),分别绑定不同数据库连接参数
- 创建一个 RoutingDataSource Bean,注入这两个数据源到其
targetDataSources,并指定一个defaultTargetDataSource - 自定义一个数据源切换工具类(如 DataSourceContextHolder),用 ThreadLocal 存储当前线程的数据源 key
- 在 RoutingDataSource 中重写
determineCurrentLookupKey(),返回DataSourceContextHolder.get()
事务管理器:每个数据源配一个 DataSourceTransactionManager
Spring 的 @Transactional 默认只认一个事务管理器。多数据源必须为每个 DataSource 显式声明对应的 PlatformTransactionManager,否则事务注解会失效或报错。
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- 为 master 数据源创建
@Bean(name = "masterTransactionManager"),类型为DataSourceTransactionManager,传入dataSourceMaster - 为 slave 数据源创建
@Bean(name = "slaveTransactionManager"),同样传入dataSourceSlave - 使用时需显式指定:
@Transactional(transactionManager = "masterTransactionManager") - 注意:单个 @Transactional 无法同时控制两个事务管理器;若需跨库原子性,必须升级为分布式事务方案
跨数据源事务:XA/JTA 或 Atomikos 等分布式事务框架
本地事务(JDBC Transaction)只能保证单库 ACID。当 insert 订单(库A)和扣减库存(库B)需要“一起成功或一起回滚”时,必须引入外部事务协调器。
- 引入 Atomikos(推荐轻量级)或 Narayana,添加对应 starter(如
atomikos-jta) - 将原 Hikari/Druid DataSource 替换为 Atomikos 提供的
AtomikosDataSourceBean,包装底层连接池 - 注册全局事务管理器
UserTransactionManager和JtaTransactionManager - 此时可用标准
@Transactional(无需指定 name),由 JTA 容器统一协调两库提交/回滚
Mapper 扫描与 SqlSessionFactory 分离
避免 Mapper 接口误绑错数据源,需按数据源隔离 SqlSessionFactory 和扫描路径:
- 为每个数据源单独定义
SqlSessionFactoryBean,注入对应 DataSource 和 MyBatis 配置(如 typeAliasesPackage、mapperLocations) - 用
@MapperScan分别指定不同包路径,并通过sqlSessionFactoryRef绑定对应 SqlSessionFactory - 例如:
@MapperScan(basePackages = "com.example.mapper.master", sqlSessionFactoryRef = "masterSqlSessionFactory") - Mapper 接口本身无需改动,但 XML 或注解 SQL 必须确保表存在于对应库中










