基于 Spring Boot 的多数据源解决方案,dynamic-datasource-spring-boot-starter 动态多数据源组件使用方法

dynamic-datasource-spring-boot-starter 使用完整指南

一、组件简介

dynamic-datasource-spring-boot-starter (简称 dynamic-datasource,国内开源多数据源框架) 核心特点:

  1. 基于 SpringBoot,无侵入,通过注解切换数据源;
  2. 支持 主从、多数据源、动态新增数据源、读写分离;
  3. 兼容 Mybatis、Mybatis-Plus、JdbcTemplate;
  4. 支持 HikariCP、Druid 连接池;

Github:https://github.com/baomidou/dynamic-datasource

⚠️ 重要提醒:不能和 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. 数据源名称规范

名称小写、不要特殊符号 ;区分大小写,Slave1slave1

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

八、和其他方案对比

  1. dynamic-datasource:注解驱动、轻量、动态新增数据源,首选方案
  2. SpringBoot 原生 AbstractRoutingDataSource:需要自己封装,不支持动态新增
  3. Sharding-JDBC:侧重分库分表,太重,单纯多数据源没必要引入

九、常见异常排查

  1. Cannot find datasource named xxx
    • 名称写错,yml 配置缩进错误;strict=true 严格校验
  2. 切换数据源不生效
    • 方法被@Transactional包裹;
    • 内部调用(this.xxx (),AOP 无法拦截),需要通过上下文获取代理对象调用;
  3. 线程复用导致数据源错乱
    • 手动切换数据源必须 clear 上下文

如果你需要,我可以提供:

  1. 完整可运行 Demo(SpringBoot3 + MybatisPlus + dynamic-datasource)
  2. Seata 整合多数据源分布式事务示例
  3. 从数据库读取数据源配置(持久化数据源,不用写死 yml)
相关推荐
带刺的坐椅5 小时前
Hot-Plug 实战:运行期管理 Solon 插件
java·solon·插件·热插拔
Lyra_Infra5 小时前
Docker OCI Runtime 启动失败问题排查与解决
后端·docker·架构
大黄说说5 小时前
SQL Server 执行计划怎么看?快速定位 SQL 慢的根源
java·linux·数据库
XuCoder5 小时前
Redis 哨兵模式:它到底是怎么保证高可用的
后端
雪之下雪乃的代码日记6 小时前
Python快速入门(Java开发者版)
java·开发语言·笔记·python
敲个大西瓜6 小时前
Springboot核心面试题
java·spring boot·后端
器灵科技6 小时前
Seedance2.5 VS MiniMax H3 同日上线:AI短剧创作者该怎么选?
java·人工智能·阿里云·prompt·aigc
xbgRS7 小时前
Mybatis源码-核心流程及核心类
java·mybatis
zzh___zzh7 小时前
Java Stream API 常用方法笔记
java·笔记
萌动的小火苗7 小时前
1、python基础面试题
java·开发语言·python