dynamic-datasource-spring-boot-starter 使用完整指南
一、组件简介
dynamic-datasource-spring-boot-starter (简称 dynamic-datasource,国内开源多数据源框架) 核心特点:
- 基于 SpringBoot,无侵入,通过注解切换数据源;
- 支持 主从、多数据源、动态新增数据源、读写分离;
- 兼容 Mybatis、Mybatis-Plus、JdbcTemplate;
- 支持 HikariCP、Druid 连接池;
⚠️ 重要提醒:不能和 SpringBoot 原生多数据源配置混用,全部数据源交由该组件管理。
二、版本依赖
Maven(pom.xml)
xml
<!-- 最新稳定版,适配SpringBoot2 / SpringBoot3 -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>dynamic-datasource-spring-boot-starter</artifactId>
<version>4.3.0</version>
</dependency>
版本选择参考:
- SpringBoot 2.x:4.1.x / 4.2.x
- SpringBoot 3.x(jakarta):4.3.0+
三、基础配置(application.yml)
场景:1 个主库 + 2 个业务库
yaml
spring:
datasource:
dynamic:
# 设置默认数据源(必须存在下面的数据源名称)
primary: master
# 是否开启严格匹配,找不到数据源抛出异常
strict: true
datasource:
# 主数据源名称:master
master:
url: jdbc:mysql://127.0.0.1:3306/db_master?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai
username: root
password: 123456
driver-class-name: com.mysql.cj.jdbc.Driver
# 从库1
slave1:
url: jdbc:mysql://127.0.0.1:3306/db_slave1?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai
username: root
password: 123456
driver-class-name: com.mysql.cj.jdbc.Driver
# 其他业务库
order:
url: jdbc:mysql://127.0.0.1:3306/db_order?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai
username: root
password: 123456
driver-class-name: com.mysql.cj.jdbc.Driver
使用 Druid 连接池(追加配置)
yaml
spring:
datasource:
dynamic:
druid:
initial-size: 5
max-active: 20
min-idle: 5
max-wait: 60000
四、核心注解使用
1. @DS 注解(核心)
作用:指定当前类 / 方法使用哪个数据源
- 加在类上:该类所有方法默认使用此数据源
- 加在方法上:优先级高于类注解(局部覆盖全局)
不添加
@DS默认使用primary: master
java
运行
import com.baomidou.dynamic.datasource.annotation.DS;
import org.springframework.stereotype.Service;
@Service
// 当前类默认使用slave1数据源
@DS("slave1")
public class UserService {
// 覆盖类注解,使用order数据源
@DS("order")
public void queryOrder() {
// 查询order库
}
// 使用类上指定的slave1
public void getUser() {
// 查询slave1库
}
}
2. 读写分离模式(简化用法)
配置支持 master(写)、slave(多个从库负载均衡)
yaml
spring:
datasource:
dynamic:
primary: master
datasource:
master: #写库
url: ...
slave_1: #读库1
url: ...
slave_2: #读库2
url: ...
java
运行
// 自动负载均衡随机选择slave组数据源
@DS("slave")
public List<User> listUser() {
}
五、动态创建数据源(运行时新增数据源)
无需重启服务,代码动态添加数据源
java
运行
import com.baomidou.dynamic.datasource.DynamicDataSourceContextHolder;
import com.baomidou.dynamic.datasource.creator.DataSourceProperty;
import com.baomidou.dynamic.datasource.creator.DefaultDataSourceCreator;
import com.baomidou.dynamic.datasource.provider.DynamicDataSourceProvider;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.sql.DataSource;
@Component
public class DynamicDsUtil {
@Autowired
private DefaultDataSourceCreator dataSourceCreator;
@Autowired
private DynamicDataSourceProvider dynamicDataSourceProvider;
/**
* 动态新增数据源
*/
public void addNewDs(String dsName) {
DataSourceProperty property = new DataSourceProperty();
property.setUrl("jdbc:mysql://127.0.0.1:3306/db_new");
property.setUsername("root");
property.setPassword("123456");
property.setDriverClassName("com.mysql.cj.jdbc.Driver");
DataSource dataSource = dataSourceCreator.createDataSource(property);
// 添加到动态数据源管理器
dynamicDataSourceProvider.addDataSource(dsName, dataSource);
}
// 手动切换数据源(代码块方式,不推荐优先使用,优先@DS)
public void manualSwitch() {
try {
DynamicDataSourceContextHolder.push("order");
// 执行业务sql
} finally {
// 必须清理,防止线程污染!
DynamicDataSourceContextHolder.clear();
}
}
}
⚠️ 手动
push一定要 finally 清除上下文,线程池场景极易数据源串库!
六、重要注意事项(踩坑重点)
1. 事务坑(高频问题)
同一个事务内,无法切换数据源! Spring 事务 @Transactional 开启时,连接会在事务开始时获取,后续 @DS 切换失效。
错误示例:
java
运行
@Transactional
public void test() {
queryMaster(); // master
@DS("slave1")
querySlave(); // ❌ 不会切换,仍然master
}
解决方案:
- 多数据源操作拆分到不同方法,不要放在同一个事务;
- 如果需要跨数据源事务,使用分布式事务(Seata AT/TCC)。
2. AOP 顺序问题
框架通过 AOP 实现数据源切换; 自定义 AOP 如果顺序不合理,会导致@DS失效。 建议自定义切面 order > -1。
3. Mybatis-Plus 分页、Mapper 扫描
无需额外改动,原生兼容,正常使用即可。
4. 数据源名称规范
名称小写、不要特殊符号 ;区分大小写,Slave1 ≠ slave1。
5. 多线程场景
DynamicDataSourceContextHolder 使用 ThreadLocal; 新开子线程无法继承父线程数据源 ,子线程需要手动设置 @DS。
七、常用配置完整参数
yaml
spring:
datasource:
dynamic:
primary: master
strict: true
# 是否开启p6spy sql日志
p6spy: false
datasource:
master:
url: jdbc:mysql://localhost:3306/db
username: root
password: 123
driver-class-name: com.mysql.cj.jdbc.Driver
八、和其他方案对比
- dynamic-datasource:注解驱动、轻量、动态新增数据源,首选方案
- SpringBoot 原生 AbstractRoutingDataSource:需要自己封装,不支持动态新增
- Sharding-JDBC:侧重分库分表,太重,单纯多数据源没必要引入
九、常见异常排查
Cannot find datasource named xxx- 名称写错,yml 配置缩进错误;strict=true 严格校验
- 切换数据源不生效
- 方法被
@Transactional包裹; - 内部调用(this.xxx (),AOP 无法拦截),需要通过上下文获取代理对象调用;
- 方法被
- 线程复用导致数据源错乱
- 手动切换数据源必须 clear 上下文
如果你需要,我可以提供:
- 完整可运行 Demo(SpringBoot3 + MybatisPlus + dynamic-datasource)
- Seata 整合多数据源分布式事务示例
- 从数据库读取数据源配置(持久化数据源,不用写死 yml)