1. Java项目中多数据源配置实战指南
在复杂的企业级Java应用中,单一数据源往往难以满足业务需求。订单数据存MySQL、用户画像存MongoDB、日志信息写Elasticsearch的场景越来越普遍。最近接手的一个电商平台改造项目,就遇到了需要同时对接传统关系型数据库和新型NoSQL数据库的需求。
多数据源配置看似简单,实则暗藏玄机。我在实际项目中踩过的坑包括:事务管理混乱导致数据不一致、连接池配置不当引发性能瓶颈、动态切换失效造成跨库查询异常等。本文将基于Spring Boot 2.7+和MyBatis-Plus 3.5+环境,分享一套经过生产验证的多数据源配置方案。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 多数据源典型应用场景解析
2.1 读写分离架构实现
大型互联网应用最常见的场景就是读写分离。我们通常配置:
- 主库(写库):负责INSERT/UPDATE/DELETE操作
- 从库(读库):承担SELECT查询压力
去年优化的一个内容管理系统,通过多数据源配置将读性能提升了3倍。关键点在于:
java复制@Configuration
@MapperScan(basePackages = "com.example.mapper.read", sqlSessionTemplateRef = "readSqlSessionTemplate")
public class ReadDataSourceConfig {
@Bean(name = "readDataSource")
@ConfigurationProperties(prefix = "spring.datasource.read")
public DataSource readDataSource() {
return DataSourceBuilder.create().build();
}
}
2.2 多类型数据库混用
现代微服务架构中,混合使用多种数据库已成常态。最近开发的物联网平台就同时使用了:
- MySQL:存储设备元数据
- MongoDB:存储时序数据
- Redis:缓存热点数据
配置要点在于为每种数据库类型创建独立的配置类:
java复制@Configuration
@EnableMongoRepositories(basePackages = "com.example.repository.mongo")
public class MongoConfig extends AbstractMongoClientConfiguration {
@Override
protected String getDatabaseName() {
return "iot_data";
}
}
2.3 多租户SaaS应用
为每个租户分配独立数据源是SaaS系统的常见做法。关键实现方案包括:
- 静态多数据源:启动时加载所有租户数据源
- 动态多数据源:运行时按需创建数据源
我们在金融SaaS项目中采用的动态方案核心代码如下:
java复制public class DynamicDataSource extends AbstractRoutingDataSource {
@Override
protected Object determineCurrentLookupKey() {
return TenantContext.getCurrentTenant();
}
public void addDataSource(String tenantId, DataSource dataSource) {
// 动态添加新数据源
}
}
3. Spring Boot多数据源完整配置
3.1 基础依赖配置
首先确保pom.xml包含必要依赖:
xml复制<dependency>
<groupId>com.baomidou</groupId>
<artifactId>dynamic-datasource-spring-boot-starter</artifactId>
<version>3.6.1</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
3.2 数据源属性配置
application.yml典型配置示例:
yaml复制spring:
datasource:
master:
url: jdbc:mysql://localhost:3306/master_db
username: root
password: 123456
driver-class-name: com.mysql.cj.jdbc.Driver
slave:
url: jdbc:mysql://localhost:3306/slave_db
username: root
password: 123456
driver-class-name: com.mysql.cj.jdbc.Driver
3.3 Java配置类实现
主数据源配置示例:
java复制@Configuration
@MapperScan(basePackages = "com.example.mapper.master",
sqlSessionFactoryRef = "masterSqlSessionFactory")
public class MasterDataSourceConfig {
@Bean(name = "masterDataSource")
@Primary
@ConfigurationProperties(prefix = "spring.datasource.master")
public DataSource masterDataSource() {
return DataSourceBuilder.create().type(HikariDataSource.class).build();
}
@Bean(name = "masterTransactionManager")
@Primary
public DataSourceTransactionManager masterTransactionManager(
@Qualifier("masterDataSource") DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
}
4. 高级配置与性能优化
4.1 连接池参数调优
生产环境推荐配置(以HikariCP为例):
yaml复制spring:
datasource:
master:
hikari:
maximum-pool-size: 20
minimum-idle: 5
connection-timeout: 30000
idle-timeout: 600000
max-lifetime: 1800000
重要提示:不同数据源的连接池应该独立配置,避免相互影响
4.2 多数据源事务管理
跨数据源事务需要引入JTA实现。我们使用Atomikos的配置示例:
java复制@Bean
public JtaTransactionManager transactionManager() {
UserTransactionManager userTransactionManager = new UserTransactionManager();
UserTransaction userTransaction = new UserTransactionImp();
return new JtaTransactionManager(userTransaction, userTransactionManager);
}
4.3 MyBatis多数据源适配
每个数据源需要独立配置SqlSessionFactory:
java复制@Bean(name = "slaveSqlSessionFactory")
public SqlSessionFactory slaveSqlSessionFactory(
@Qualifier("slaveDataSource") DataSource dataSource) throws Exception {
SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
bean.setDataSource(dataSource);
bean.setMapperLocations(
new PathMatchingResourcePatternResolver()
.getResources("classpath:mapper/slave/*.xml"));
return bean.getObject();
}
5. 常见问题排查手册
5.1 数据源切换失效问题
症状:@DS注解不生效,始终使用默认数据源
排查步骤:
- 检查是否在启动类添加了@EnableDynamicDataSource
- 确认方法调用是否来自类外部(AOP代理要求)
- 查看是否有更高优先级的事务注解覆盖
5.2 连接泄漏诊断
监控指标:
java复制HikariDataSource master = (HikariDataSource)masterDataSource();
log.info("Active connections: {}", master.getHikariPoolMXBean().getActiveConnections());
5.3 性能瓶颈分析
推荐使用Arthas进行诊断:
bash复制# 监控JDBC查询耗时
watch org.springframework.jdbc.core.JdbcTemplate query '{params,returnObj}' '#cost>100' -x 3
6. 生产环境最佳实践
6.1 监控配置要点
每个数据源应独立监控:
java复制@Bean
public MeterRegistryCustomizer<MeterRegistry> metricsCommonTags() {
return registry -> registry.config().commonTags(
"dataSource", dataSourceName);
}
6.2 故障转移策略
建议配置备用数据源:
java复制@Bean
@Primary
public DataSource routingDataSource() {
Map<Object, Object> targetDataSources = new HashMap<>();
targetDataSources.put("master", masterDataSource());
targetDataSources.put("standby", standbyDataSource());
AbstractRoutingDataSource routing = new AbstractRoutingDataSource() {
@Override
protected Object determineCurrentLookupKey() {
return MasterStatusChecker.isMasterAvailable() ? "master" : "standby";
}
};
routing.setDefaultTargetDataSource(masterDataSource());
routing.setTargetDataSources(targetDataSources);
return routing;
}
6.3 安全加固建议
- 每个数据源使用不同账号
- 定期轮换数据库密码
- 敏感配置加密处理:
java复制@Bean
public DataSource masterDataSource(
@Value("${spring.datasource.master.url}") String url,
@Value("${spring.datasource.master.username}") String username,
@Value("${spring.datasource.master.password}") String password) {
return DataSourceBuilder.create()
.url(decrypt(url))
.username(decrypt(username))
.password(decrypt(password))
.build();
}
在最近一次金融级项目审计中,这套配置方案成功通过了以下检验:
- 2000+ TPS压力测试下无连接泄漏
- 跨数据源事务一致性验证
- 故障切换时间<3秒
- 安全扫描无高危漏洞
实际开发时,建议根据业务场景适当简化配置。对于中小型项目,可以使用dynamic-datasource-spring-boot-starter快速起步,等业务复杂度上升后再逐步引入更精细的管控策略。
