多数据源(MyBatis)入门
1. 一句话简介
多数据源是指一个应用同时连接并操作多个数据库(如一个主库 master 和一个从库 slave),并按需在不同库之间切换访问的能力。本模块所演示的是基于苞米豆(baomidou)团队的 dynamic-datasource-spring-boot-starter + MyBatis-Plus 实现的方案:只需在 application.yml 中声明多个数据源,再在 Service 上打一个 @DS 注解即可完成数据源切换,框架底层通过 AOP 拦截在方法执行前后动态路由到目标库。
其核心价值在于解决「一个业务系统同时访问多个数据库」的问题——尤其是读写分离和分库访问这两种最常见的诉求,同时把传统方案中需要手写多套 DataSource、SqlSessionFactory、TransactionManager 的繁琐配置彻底简化。
2. 什么时候使用
✅ 适用场景:
- 读写分离:MySQL 主从复制架构下,写操作走主库、读操作走从库,通过类级别
@DS("slave")+ 方法级别@DS("master")即可优雅路由,这正是本 demo 的核心演示逻辑(addUser写主库,list读从库)。 - 多库按业务隔离:不同业务模块使用不同的数据库,同一应用中按 Service 或方法粒度访问不同库,避免把所有表堆在同一个库里。
- 追求低成本接入:团队已采用 MyBatis-Plus,希望数据源切换尽量少写样板代码——纯注解驱动,无需业务代码感知数据源实现细节。
- 需要灵活切换、动态路由:路由规则可能随时间变化,希望用注解在方法粒度精确控制,而非靠包路径这类编译期绑定的方式。
❌ 不适用 / 需谨慎:
- 跨库强一致事务:
@DS本质是路由不同的物理连接,跨数据源的分布式事务需要额外引入 Seata、XA 等方案,否则无法保证 ACID。若业务强依赖跨库事务,单库或多数据源 + 分布式事务方案更合适。 - 数据真正需要跨库关联查询:多数据源的多个库之间无法用一条 SQL 做 JOIN,需在应用层分别查询再合并,性能与开发成本都会上升。此时应考虑分库分表中间件(如 ShardingSphere)或合并为单库。
- 需要复杂路由策略:若路由依赖用户身份、租户、请求参数等运行时上下文做动态决策,纯注解模式的扩展性有限,需要扩展自定义切面或改用分库分表组件。
- 已用 JPA/其他 ORM 且仅需完全隔离的多库:若只是「几个独立库之间互不切换」,包路径隔离式的 JPA 方案或独立配置也足够,不一定需要动态数据源框架。
3. 常见业务场景
MySQL 主从读写分离:这是最经典的应用。生产环境搭建 MySQL 主从复制后,将写操作(INSERT/UPDATE/DELETE)路由到 master 主库、查询操作路由到 slave 从库,有效分担主库读压力。如本 demo,UserServiceImpl 类上 @DS("slave") 让 list、save 默认走从库,仅对有写需求的 addUser 方法标注 @DS("master"),实现读写分离而无需改动业务 SQL。
多租户/多业务数据库隔离:中后台系统把用户服务、订单服务、日志服务拆到不同数据库,甚至每个租户拥有独立库。通过 @DS 在每个 Service 上指定对应库别名,即可在同一应用内按业务组织数据,避免大量表耦合在单个库影响性能与运维。
报表与分析类只读库:把高频交易的业务库与低频的分析报表库分离,报表相关 Mapper 统一路由到只读的从库或数仓,查询不阻塞主库写入,同时通过 master/slave 别名区分两类连接。
灰度/多环境数据源切流:同一套代码在切换不同数据源时只需修改 application.yml 或通过配置中心的别名映射,配合 @DS 注解即可在开发、测试、生产或新旧库之间快速切换,便于平滑迁移。
系统解耦下的共享数据访问:多个子系统共享一套基础数据(用户、配置),但各自连接的主库节点不同,通过动态数据源让同一份服务代码按落地环境路由到对应的基础库。
4. 同类技术对比
| 对比维度 | dynamic-datasource + MyBatis-Plus(本模块) | 原生 MyBatis 多数据源 | Spring Data JPA 多数据源 | ShardingSphere-JDBC(分库分表/读写分离) |
|---|---|---|---|---|
| 数据源切换方式 | @DS 注解,方法/类粒度,运行时动态 |
手写多套 DataSource/SqlSessionFactory,包路径隔离 |
编译期固定,靠 @Primary + 多 repo 包划分 |
配置规则 + 内置负载均衡策略,SQL 级自动路由 |
| 配置复杂度 | 低(YAML + 注解) | 高(多套 Bean 与事务管理器) | 高(多 EntityManagerFactory/TransactionManager) |
中(需理解分片/读写规则配置) |
| 读写分离支持 | 支持,注解显式指定主从 | 支持,需自行维护 | 支持,但需额外 workaround | 内置读写分离 + 负载均衡,开箱即用 |
| 分布式/跨库能力 | 弱(仅动态路由,跨库事务需外部组件) | 弱 | 弱 | 强(分片、广播表、跨库查询 SQL 解析) |
| 关联查询能力 | 不支持跨库 JOIN | 不支持 | 不支持 | 支持一定范围的分片内 JOIN |
| 学习成本 | 低,围绕 MyBatis-Plus 生态 | 中,需理解多套 Bean 管理 | 中,需理解 JPA 多 EntityManager | 高,概念多(分片键、绑定表、广播表) |
| 适用规模 | 中小规模,主从 + 少量业务多库 | 需要细粒度手控的小场景 | JPA 阵营的多库隔离 | 中大规模,数据量大、需横向拆分的场景 |
| 事务管理 | 由框架协调单库事务,跨库不保证 | 每套数据源独立事务管理器 | 每套数据源独立事务管理器 | 提供分布式事务扩展(Seata/XA) |
选型建议:
- 团队深度使用 MyBatis-Plus、需要「注解级」简单切换的读写分离或多库访问:优先
dynamic-datasource-spring-boot-starter。接入成本最低,与 MyBatis-Plus 无缝集成,适合绝大多数中小型业务。 - 数据量持续增长、需要真正的分片/水平拆分、或要跨库聚合查询:应选择 ShardingSphere-JDBC 这类分库分表中间件,动态数据源只解决「路由」不解决「分片」,此时能力已不够。
- 技术栈偏 JPA/Repository 风格,且各库完全独立、互不切换:使用原生 JPA 多数据源即可,避免为简单需求引入框架依赖。
- 需要底层的完全掌控,或依赖极少数特定 Mapper 的行为定制:原生 MyBatis 多
SqlSessionFactory方案更直接,但需接受更高的配置复杂度和潜在的事务协调成本。