1. 为什么需要多数据源配置?
在实际开发中,我们经常会遇到需要同时操作多个数据库的场景。比如:
- 读写分离:主库负责写操作,从库负责读操作
- 分库分表:数据量过大时,将数据分散到不同的数据库实例
- 多租户系统:每个租户有自己独立的数据库
- 异构数据源:需要同时访问MySQL、Oracle等不同类型的数据库
传统的单数据源配置显然无法满足这些需求。MyBatis-Plus作为MyBatis的增强工具,提供了简洁高效的多数据源解决方案。
注意:多数据源配置会增加系统复杂度,如果不是必要场景,建议优先考虑单数据源方案。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 核心组件选型与版本匹配
2.1 dynamic-datasource-spring-boot-starter介绍
MyBatis-Plus官方推荐使用dynamic-datasource-spring-boot-starter来实现多数据源管理。这个组件具有以下特点:
- 基于Spring Boot的自动配置
- 支持数据源分组
- 提供简单的注解切换方式
- 内置多种数据源(Druid、HikariCP等)
- 支持Seata分布式事务
2.2 版本兼容性
根据热词搜索,很多开发者关心版本匹配问题。以下是经过验证的稳定版本组合:
- Spring Boot: 2.7.x
- MyBatis-Plus: 3.5.17
- dynamic-datasource: 3.6.1
- Druid: 1.2.8
提示:版本不匹配是常见问题,建议严格按照官方文档推荐的组合使用。
3. 完整配置流程
3.1 添加依赖
首先在pom.xml中添加必要依赖:
xml复制<dependency>
<groupId>com.baomidou</groupId>
<artifactId>dynamic-datasource-spring-boot-starter</artifactId>
<version>3.6.1</version>
</dependency>
<!-- 使用Druid连接池 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.2.8</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.17</version>
</dependency>
3.2 配置文件设置
在application.yml中配置多数据源:
yaml复制spring:
datasource:
dynamic:
primary: master # 设置默认数据源
strict: false # 是否严格匹配数据源
datasource:
master:
url: jdbc:mysql://localhost:3306/master_db
username: root
password: 123456
driver-class-name: com.mysql.cj.jdbc.Driver
type: com.alibaba.druid.pool.DruidDataSource
druid:
initial-size: 5
max-active: 20
min-idle: 5
slave1:
url: jdbc:mysql://localhost:3306/slave1_db
username: root
password: 123456
driver-class-name: com.mysql.cj.jdbc.Driver
type: com.alibaba.druid.pool.DruidDataSource
3.3 使用@DS注解切换数据源
在Service层或Mapper层使用@DS注解来指定数据源:
java复制@Service
@DS("master") // 默认使用master数据源
public class UserServiceImpl implements UserService {
@Autowired
private UserMapper userMapper;
@Override
@DS("slave1") // 这个方法使用slave1数据源
public List<User> getAllUsers() {
return userMapper.selectList(null);
}
}
4. 高级配置与优化
4.1 自定义数据源配置
如果需要更精细的控制,可以创建配置类:
java复制@Configuration
public class DataSourceConfig {
@Bean
@ConfigurationProperties("spring.datasource.dynamic.datasource.master")
public DataSource masterDataSource() {
return DruidDataSourceBuilder.create().build();
}
@Bean
@ConfigurationProperties("spring.datasource.dynamic.datasource.slave1")
public DataSource slave1DataSource() {
return DruidDataSourceBuilder.create().build();
}
}
4.2 事务管理
多数据源环境下,事务管理需要特别注意:
java复制@Service
public class OrderService {
@Autowired
private OrderMapper orderMapper;
@Autowired
private UserMapper userMapper;
@Transactional(rollbackFor = Exception.class)
public void createOrder(Order order) {
// 默认使用master数据源
orderMapper.insert(order);
// 需要手动指定事务管理器
TransactionTemplate transactionTemplate = new TransactionTemplate(transactionManager);
transactionTemplate.execute(status -> {
// 这里使用slave1数据源
userMapper.updatePoints(order.getUserId(), -order.getPoints());
return null;
});
}
}
4.3 动态添加数据源
运行时动态添加数据源:
java复制@Autowired
private DynamicRoutingDataSource dynamicRoutingDataSource;
public void addDataSource(String dsName, DataSourceProperty property) {
DataSource dataSource = dynamicDataSourceCreator.createDataSource(property);
dynamicRoutingDataSource.addDataSource(dsName, dataSource);
}
5. 常见问题排查
5.1 数据源切换不生效
可能原因:
- 方法调用发生在同一个类内部,Spring AOP代理失效
- @DS注解位置不正确
- 数据源名称拼写错误
解决方案:
- 确保@DS注解的方法是通过Spring代理调用的
- 检查数据源名称是否与配置一致
- 在启动时添加
spring.datasource.dynamic.strict=true可以严格检查数据源
5.2 事务问题
多数据源环境下,跨数据源的事务需要使用分布式事务解决方案如Seata:
java复制@GlobalTransactional
public void crossDataSourceOperation() {
// 操作master数据源
masterMapper.update();
// 操作slave数据源
slaveMapper.update();
}
5.3 性能优化建议
- 合理设置连接池参数
- 监控数据源使用情况
- 避免频繁切换数据源
- 对读多写少的场景,可以配置多个从库并实现负载均衡
6. 实际案例:读写分离实现
下面是一个完整的读写分离实现示例:
6.1 配置多个从库
yaml复制spring:
datasource:
dynamic:
datasource:
master:
# 主库配置
slave1:
# 从库1
slave2:
# 从库2
slave:
enabled: true
load-balance-type: round_robin # 轮询负载均衡
6.2 使用负载均衡
java复制@Service
public class UserService {
@DS("slave") // 使用从库组
public List<User> queryUsers() {
// 会自动在slave1和slave2之间轮询
return userMapper.selectList(null);
}
@DS("master") // 写操作使用主库
public void addUser(User user) {
userMapper.insert(user);
}
}
6.3 监控数据源
添加以下配置开启监控:
yaml复制spring:
datasource:
druid:
stat-view-servlet:
enabled: true
url-pattern: /druid/*
login-username: admin
login-password: admin
web-stat-filter:
enabled: true
url-pattern: /*
exclusions: "*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*"
7. 与若依框架集成
对于使用若依框架4.8.3版本想迁移到MyBatis-Plus的开发者,需要注意:
- 替换mybatis依赖为mybatis-plus
- 修改原有Mapper接口继承BaseMapper
- 调整分页配置:
java复制@Configuration
public class MybatisPlusConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
return interceptor;
}
}
- 原有XML中的分页查询需要调整为MyBatis-Plus风格
8. 最佳实践与经验分享
在实际项目中,我总结了以下几点经验:
- 命名规范:数据源名称使用有意义的单词,避免ds1、ds2这种无意义的命名
- 监控告警:配置合理的监控,及时发现连接泄露等问题
- 压测验证:上线前进行充分的压力测试,验证多数据源配置的稳定性
- 文档记录:详细记录每个数据源的用途和配置参数
- 故障演练:模拟主库故障,验证从库切换是否正常
一个常见的坑是忘记配置主库的primary属性,导致系统不知道默认使用哪个数据源。建议在配置中显式指定:
yaml复制spring:
datasource:
dynamic:
primary: master # 明确指定主库
另外,对于分页查询,MyBatis-Plus提供了很方便的封装:
java复制@DS("slave")
public Page<User> queryUsers(int pageNum, int pageSize) {
Page<User> page = new Page<>(pageNum, pageSize);
return userMapper.selectPage(page, null);
}
最后提醒一点,多数据源配置会增加系统复杂度,建议在真正需要时才使用。对于简单的读写分离,也可以考虑使用MySQL自带的主从复制配合路由规则来实现。
