Spring Boot不能直接用DataSourceAutoConfiguration是因为其默认只识别单级spring.datasource.*前缀,不支持多数据源嵌套配置,必须显式排除该自动配置类,再手动为各数据源(如Oracle、MySQL)分别定义绑定前缀的配置类、DataSource Bean及对应事务管理器,并确保SqlSessionFactory、@MapperScan和@Transactional正确关联指定Bean。
为什么不能直接用 DataSourceAutoConfiguration
spring boot 默认会自动配置一个 datasource,一旦你在 application.yml 里写两个数据源(比如 spring.datasource.oracle 和 spring.datasource.mysql),它就会报错:cannot determine embedded database driver class for database type none。根本原因是自动配置机制只认单个 spring.datasource.* 前缀,不支持嵌套多级结构的原生识别。
所以必须显式排除自动配置:
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
注意:不是禁用整个 JDBC 或 MyBatis 自动配置,只关掉数据源那一环。否则 SqlSessionFactoryBean、事务管理器等后续组件会初始化失败。
如何为 Oracle 和 MySQL 分别定义 DataSource 配置类
每个数据源需要独立的 @Configuration 类,核心是三要素:数据源属性绑定、数据源实例构建、事务管理器声明。不能共用同一个 @Primary,否则 Spring 无法区分。
-
OracleDataSourceConfig中必须用@ConfigurationProperties("spring.datasource.oracle")绑定配置项,且@Bean方法名不能叫dataSource(避免和默认 Bean 冲突),建议命名为oracleDataSource() -
MySQLDataSourceConfig同理,前缀改为"spring.datasource.mysql",方法命名为mysqlDataSource() - 两个类中都需声明各自的
DataSourceTransactionManager,例如mysqlTransactionManager()和oracleTransactionManager(),否则@Transactional注解会默认走第一个被加载的事务管理器,导致跨库事务失效 - Oracle 的 JDBC URL 格式要小心:
jdbc:oracle:thin:@host:port:SID或jdbc:oracle:thin:@//host:port/service_name,用错会导致Io exception: Connection refused
MyBatis 的 SqlSessionFactory 怎么跟指定数据源绑定
关键在 SqlSessionFactoryBean.setDataSource() —— 它必须指向你手动创建的那个 DataSource Bean,而不是靠扫描或默认注入。
以 MySQL 为例:
@Bean
@Qualifier("mysqlSqlSessionFactory")
public SqlSessionFactory mysqlSqlSessionFactory() throws Exception {
SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
factoryBean.setDataSource(mysqlDataSource()); // ← 显式传入
factoryBean.setMapperLocations(
new PathMatchingResourcePatternResolver()
.getResources("classpath:mapper/mysql/**/*.xml")
);
factoryBean.setConfiguration(mybatisConfig());
return factoryBean.getObject();
}
常见错误:
- 忘记调用
setDataSource(),导致 MyBatis 默认使用 Spring Boot 自动装配的(已排除)空数据源,运行时报java.lang.IllegalStateException: No DataSource set -
@MapperScan的basePackages和sqlSessionFactoryRef不匹配:比如basePackages="com.example.mapper.mysql"却没配sqlSessionFactoryRef="mysqlSqlSessionFactory",Mapper 接口会找不到对应 SessionFactory - Oracle 的
mapper-locations路径里用了 MySQL 的方言 SQL(如limit、auto_increment),执行时报ORA-00933: SQL command not properly ended
事务切换失败时先查 TransactionManagementConfigurer 是否漏了
如果你写了 @Transactional(transactionManager = "mysqlTransactionManager") 却发现还是操作了 Oracle 表,大概率是没让 Spring 知道你提供了多个事务管理器实现。
必须加一个配置类实现 TransactionManagementConfigurer 接口:
@Configuration
public class TransactionConfiguration implements TransactionManagementConfigurer {
@Override
public PlatformTransactionManager annotationDrivenTransactionManager() {
// 返回任意一个作为默认,但必须返回
return mysqlTransactionManager();
}
}
这个接口的作用是告诉 Spring:“我有多个事务管理器,别瞎猜,默认用这个”。没有它,@Transactional 的 transactionManager 属性会被忽略,永远走默认那个。
另外注意:Spring 的事务代理默认是 JDK 动态代理,如果 service 方法是 private 或者被同一类内其他方法调用,事务不会生效——这点和单数据源一样,但多数据源下更容易误判为“切换失败”。











