
1. 为什么需要多数据源配置在传统SpringBoot项目中我们通常只需要配置一个数据源就能满足大部分业务需求。但实际开发中多数据源的需求非常普遍主要源于以下几种场景读写分离主库负责写操作从库负责读操作减轻主库压力分库分表数据量过大时将数据分散到不同数据库实例多租户系统每个租户使用独立的数据源异构数据源同时连接MySQL、Oracle、PostgreSQL等不同类型数据库数据迁移新旧系统并行运行期间需要同时访问新旧数据库提示多数据源配置虽然强大但也会带来事务管理复杂化的问题需要特别注意分布式事务的处理。2. 环境准备与基础配置2.1 项目初始化首先创建一个标准的SpringBoot项目添加以下核心依赖dependencies !-- SpringBoot Starter -- dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-web/artifactId /dependency !-- MyBatis-Plus Starter -- dependency groupIdcom.baomidou/groupId artifactIdmybatis-plus-boot-starter/artifactId version3.5.2/version /dependency !-- 数据库驱动 -- dependency groupIdmysql/groupId artifactIdmysql-connector-java/artifactId scoperuntime/scope /dependency !-- 多数据源支持 -- dependency groupIdcom.baomidou/groupId artifactIddynamic-datasource-spring-boot-starter/artifactId version3.5.1/version /dependency /dependencies2.2 数据源配置在application.yml中配置多个数据源spring: datasource: dynamic: primary: master # 设置默认数据源 datasource: master: url: jdbc:mysql://localhost:3306/master_db?useSSLfalseserverTimezoneUTC username: root password: 123456 driver-class-name: com.mysql.cj.jdbc.Driver slave: url: jdbc:mysql://localhost:3306/slave_db?useSSLfalseserverTimezoneUTC username: root password: 123456 driver-class-name: com.mysql.cj.jdbc.Driver3. MyBatis-Plus多数据源实现3.1 数据源切换策略MyBatis-Plus通过DS注解实现数据源切换支持以下两种方式方法级别注解在Service方法上标注类级别注解在Service类上标注对该类所有方法生效Service DS(slave) // 类级别注解默认使用slave数据源 public class UserServiceImpl extends ServiceImplUserMapper, User implements UserService { Override DS(master) // 方法级别注解覆盖类级别注解 public boolean save(User entity) { return super.save(entity); } Override public User getById(Serializable id) { return super.getById(id); // 使用slave数据源 } }3.2 事务管理注意事项多数据源环境下事务管理需要特别注意不支持跨数据源事务一个事务方法内不能切换数据源事务传播行为Transactional和DS注解同时存在时事务注解必须放在DS上方Transactional DS(master) public void businessMethod() { // 业务逻辑 }4. 高级配置与优化4.1 动态数据源路由对于更复杂的场景可以实现自定义数据源路由策略public class CustomDataSourceRouter extends AbstractRoutingDataSource { Override protected Object determineCurrentLookupKey() { // 根据当前线程上下文决定使用哪个数据源 return DataSourceContextHolder.getDataSource(); } }4.2 多数据源性能优化连接池配置为每个数据源单独配置连接池参数监控与统计集成Druid等监控工具故障转移实现数据源自动切换机制spring: datasource: dynamic: datasource: master: hikari: maximum-pool-size: 20 minimum-idle: 5 slave: hikari: maximum-pool-size: 30 minimum-idle: 105. 常见问题排查5.1 数据源切换失效可能原因及解决方案问题现象可能原因解决方案DS注解不生效注解位置错误确保注解在Service类/方法上事务内切换失败事务传播冲突调整注解顺序或拆分方法动态路由无效上下文未正确设置检查DataSourceContextHolder实现5.2 性能问题分析多数据源环境下常见的性能瓶颈连接泄漏未正确关闭数据库连接跨库JOIN避免在应用层做跨库关联查询连接池竞争合理设置各数据源连接池大小我在实际项目中发现当主从延迟较大时从库查询可能会返回旧数据。针对这种情况我们可以在代码中添加重试机制或降级策略Retryable(maxAttempts 3, backoff Backoff(delay 100)) DS(slave) public User getLatestUser(Long id) { return userMapper.selectById(id); }6. 最佳实践与经验分享经过多个项目的实践我总结了以下多数据源配置的最佳实践命名规范数据源名称要有明确含义如order_master、user_slave等监控告警为每个数据源设置独立的监控指标文档记录维护数据源矩阵文档记录各数据源的用途、配置参数等测试策略编写专门的集成测试验证数据源切换逻辑一个典型的项目结构建议src/main/java ├── config │ ├── datasource │ │ ├── DynamicDataSourceConfig.java │ │ └── DataSourceRouter.java ├── context │ └── DataSourceContextHolder.java ├── service │ ├── impl │ │ ├── OrderServiceImpl.java │ │ └── UserServiceImpl.java对于新项目我建议从简单配置开始随着业务复杂度增加再逐步引入更高级的特性。初期可以先用DS注解实现基本的多数据源需求等真正需要动态路由时再实现自定义路由策略。在微服务架构下如果多数据源需求变得过于复杂可能需要考虑将服务拆分为多个独立服务每个服务只负责一个数据源。这种架构虽然增加了服务数量但简化了每个服务的复杂度更易于维护和扩展。