Spring里头咋整两个数据库连接,配置和用法那些事儿分享下
- 问答
- 2026-01-08 10:36:17
- 7
行,那咱们就直接唠唠在Spring项目里怎么整两个数据库连接这事儿,这事儿说白了,就是让你的应用能同时跟两个不同的数据库“对话”,你可能需要从一个老系统(数据库A)里读点基础数据,然后运算完了再把结果写到另一个新库(数据库B)里去。
为啥要整两个连接?
最常见的就是“读写分离”,为了减轻主数据库的压力,通常会把写操作(增删改)都给主库,而把查询的活儿交给另一个专门负责读的从库,再比如,你的应用可能需要连接一个自己业务的核心数据库,同时还得从公司另一个独立的项目数据库里拉取数据,这时候也得配俩连接。
怎么配?核心就是两套配置
Spring Boot让这个事变得简单了不少,核心思路就是为每个数据库定义一套独立的配置“班子”:数据源(DataSource)、负责数据库会话的SqlSessionFactory、事务管理器(TransactionManager)等等,你得让Spring清楚,哪些Bean是伺候第一个库的,哪些是伺候第二个库的,别让它们搞混了。
下面我以经典的MyBatis框架为例,说说最常用的配置方法。
在application.yml里把两个数据库的信息都写上
得在配置文件(比如application.yml)里把两个数据库的连接信息都声明了,这里不能用默认的spring.datasource了,得给它们起个名区分开。

# 第一个数据库,我们管它叫 primary-db,是主库
primary:
datasource:
url: jdbc:mysql://localhost:3306/db_primary?useSSL=false
username: root
password: 123456
driver-class-name: com.mysql.cj.jdbc.Driver
# 第二个数据库,我们管它叫 secondary-db,是从库或另一个业务库
secondary:
datasource:
url: jdbc:mysql://localhost:3306/db_secondary?useSSL=false
username: root
password: 123456
driver-class-name: com.mysql.cj.jdbc.Driver
用Java代码来配置每个数据库的“工作小组”
光有连接信息还不够,我们需要用Java配置类来创建每个数据库需要的各种工具Bean。
- 配置主数据库(primary-db)
我们创建一个配置类,比如叫PrimaryDataSourceConfig,在这个类头上,我们用@Configuration告诉Spring这是个配置类,再用@MapperScan指定扫描哪个包下面的Mapper接口是归这个数据库管的,同时要指明用哪个SqlSessionFactory和事务管理器。
@Configuration
// 重点:指定扫描mapper接口的包,并指定这个库专用的sqlSessionFactory和transactionManager
@MapperScan(basePackages = "com.example.mapper.primary",
sqlSessionFactoryRef = "primarySqlSessionFactory",
transactionManagerRef = "primaryTransactionManager")
public class PrimaryDataSourceConfig {
// 读取配置文件中 primary.datasource 开头的属性,构造第一个数据源
@Bean(name = "primaryDataSource")
@ConfigurationProperties(prefix = "primary.datasource")
public DataSource primaryDataSource() {
// 这里用HikariCP连接池,Spring Boot 2.x默认就是这个,性能好
return DataSourceBuilder.create().type(HikariDataSource.class).build();
}
// 创建第一个数据库专用的SqlSessionFactory
@Bean(name = "primarySqlSessionFactory")
public SqlSessionFactory primarySqlSessionFactory(@Qualifier("primaryDataSource") DataSource dataSource) throws Exception {
SqlSessionFactoryBean sessionFactoryBean = new SqlSessionFactoryBean();
sessionFactoryBean.setDataSource(dataSource);
// 如果你的MyBatis映射文件XML和这个配置类不在默认位置,可以在这里设置路径
// sessionFactoryBean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:mapper/primary/*.xml"));
return sessionFactoryBean.getObject();
}
// 创建第一个数据库专用的事务管理器
@Bean(name = "primaryTransactionManager")
public DataSourceTransactionManager primaryTransactionManager(@Qualifier("primaryDataSource") DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
}
- 配置第二个数据库(secondary-db)
第二个库的配置类写法几乎一模一样,就是改个名字,指向的配置前缀和扫描的包路径要换掉。

@Configuration
// 重点:扫描的包换成 secondary 的,引用的Bean名字也全换成 secondary 开头的
@MapperScan(basePackages = "com.example.mapper.secondary",
sqlSessionFactoryRef = "secondarySqlSessionFactory",
transactionManagerRef = "secondaryTransactionManager")
public class SecondaryDataSourceConfig {
@Bean(name = "secondaryDataSource")
@ConfigurationProperties(prefix = "secondary.datasource")
public DataSource secondaryDataSource() {
return DataSourceBuilder.create().type(HikariDataSource.class).build();
}
@Bean(name = "secondarySqlSessionFactory")
public SqlSessionFactory secondarySqlSessionFactory(@Qualifier("secondaryDataSource") DataSource dataSource) throws Exception {
SqlSessionFactoryBean sessionFactoryBean = new SqlSessionFactoryBean();
sessionFactoryBean.setDataSource(dataSource);
return sessionFactoryBean.getObject();
}
@Bean(name = "secondaryTransactionManager")
public DataSourceTransactionManager secondaryTransactionManager(@Qualifier("secondaryDataSource") DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
}
具体怎么用?
配置好了,用法就简单了。
- 分包管理:最清晰的用法是把不同数据库的Mapper接口和对应的XML映射文件也分开放,操作主库的Mapper接口都放在
com.example.mapper.primary包下,操作第二个库的都放在com.example.mapper.secondary包下,这样,上面配置里的@MapperScan就能自动把它们分别关联到正确的数据库上。 - 在Service里注入使用:在你的业务Service里,你想用哪个库的Mapper,就直接
@Autowired注入哪个,Spring会根据包路径和我们的配置,自动把正确的Mapper实例给你注入进来。
@Service
public class SomeService {
@Autowired
private PrimaryMapper primaryMapper; // 这个接口在 primary 包下,会自动用主库连接
@Autowired
private SecondaryMapper secondaryMapper; // 这个接口在 secondary 包下,会自动用第二个库连接
public void someBusinessMethod() {
// 从第二个库读数据
SomeData dataFromSecondary = secondaryMapper.selectSomeData();
// 经过一些业务处理...
// 把结果写入主库
primaryMapper.insertResult(dataFromSecondary);
}
}
事务问题要注意
如果一个Service方法需要同时操作两个数据库,并且要保证一致性(要么都成功,要么都失败),这就涉及到分布式事务了,比较复杂,Spring自带的事务管理器(@Transactional)默认只能管一个数据源,在你上面的方法上如果只写@Transactional,它默认只会管理那个被标记为@Primary的数据源的事务。
对于这种跨库的事务,简单的办法可能是在代码里做补偿(一个成功了,另一个失败了,就手动回滚第一个),如果对一致性要求极高,就需要引入像JTA这样的分布式事务解决方案,或者使用Seata这类中间件,但那配置起来就麻烦多了,通常在这种多数据源场景下,会尽量设计业务,避免跨库的分布式事务。
总结一下:整两个数据库连接,关键就是“分家”——配置分开、Bean名字分开、Mapper接口的包分开,配的时候细心点,别让Bean打架,用的时候根据包路径注入,就基本没啥大问题了,事务那块儿是难点,需要根据实际业务需求来权衡处理方案。
本文由邝冷亦于2026-01-08发表在笙亿网络策划,如有疑问,请联系我们。
本文链接:https://www.haoid.cn/wenda/76758.html
