Spring Boot 配置多个 Oracle 数据源时,必须使用 oracle.jdbc.driver.OracleDriver 或 oracle.jdbc.OracleDriver(非 com.oracle.jdbc.Driver),application.yml 缩进需严格对齐,ojdbc8 必须引入并配置 ?oracle.net.disableOob=true,且每个数据源需独立 SqlSessionFactory、MapperScan 路径及 DataSourceTransactionManager。
配置多个Oracle数据源时,application.yml缩进和driver-class-name必须严格匹配
oracle驱动类名容易写错,com.oracle.jdbc.driver 是过时写法,spring boot 2.4+ 必须用 oracle.jdbc.driver.oracledriver(旧版)或更推荐的 oracle.jdbc.oracledriver(12c+)。同时,yaml中每个数据源的层级缩进不能错——spring.datasource.db1.url 和 spring.datasource.db1.username 必须对齐,否则 @configurationproperties 绑定失败,启动时抛 bindingexception 或静默忽略配置。
- 检查
ojdbc8(对应 Oracle 12c/19c)是否已引入,避免用ojdbc6导致 TLS 握手失败 - URL 中必须含
?oracle.net.disableOob=true(尤其在高并发下防止连接中断) - 多个 Oracle 数据源共用同一 driver class 时,不要在每个
@Bean上重复指定driver-class-name,统一由DataSourceBuilder自动识别
DynamicDataSource 继承 AbstractRoutingDataSource 时,determineCurrentLookupKey 返回 null 会 fallback 到默认数据源
determineCurrentLookupKey() 方法返回 null 不会报错,而是触发 AbstractRoutingDataSource 的 fallback 逻辑:使用 setDefaultTargetDataSource() 设置的那个数据源。这常被误认为“切换失败”,其实是设计行为。
- 确保
DynamicDataSourceContextHolder.getDataSourceType()在调用前已被设置,否则返回null - 不要在
finally块里调用clear()后又执行 DAO 操作——MyBatis 的SqlSession可能复用线程上下文,导致后续查询走错库 - 若用 AOP 切面切换,注解方法内嵌套调用其他 Service 方法时,需显式加
@DS("db2"),否则子方法沿用父方法的数据源,而非自动继承
Oracle 多数据源 + MyBatis 场景下,Mapper 扫描路径和 @MapperScan 必须按数据源分组
MyBatis 默认只认一个 SqlSessionFactory,多个 Oracle 数据源意味着你需要多个 SqlSessionFactory 实例,每个绑定不同 DataSource 和独立的 @MapperScan 路径。否则会出现 “找不到 Mapper” 或 “所有查询都走同一个库”。
- 为
db1配置@MapperScan(basePackages = "com.example.mapper.db1", sqlSessionFactoryRef = "sqlSessionFactoryDb1") -
sqlSessionFactoryDb1的dataSource属性必须指向@Bean(name = "db1") DataSource,不可引用dynamicDataSource - XML 映射文件(
*.xml)路径要与接口包结构一致,且需在mybatis.mapper-locations中显式列出,例如:classpath:mapper/db1/*.xml
事务管理器必须与动态数据源强绑定,@Transactional 默认不感知数据源切换
Spring 的 @Transactional 注解默认使用 PlatformTransactionManager bean,而该 bean 若只注入了 dynamicDataSource,则事务只会围绕这个路由数据源展开——但实际执行时可能已切到 db2,导致事务隔离失效或回滚不生效。
- 必须为每个物理数据源定义独立的
DataSourceTransactionManager,例如transactionManagerDb1和transactionManagerDb2 - 在 Service 方法上使用
@Transactional(transactionManager = "transactionManagerDb2")显式指定 - 跨数据源事务(如 db1 写 + db2 写)无法用本地事务保证一致性,必须改用 Saga 或消息最终一致性,不要尝试
@Transactional跨两个 manager


















