SpringBoot多数据源dynamic-datasource快速入门
mhr18 2025-07-01 22:08 5 浏览 0 评论
一、简介
dynamic-datasourc是一个基于 SpringBoot 的快速集成多数据源的启动器,其主要特性如下:
- 支持 数据源分组 ,适用于多种场景 纯粹多库 读写分离 一主多从 混合模式。
- 支持数据库敏感配置信息 加密 ENC()。
- 支持每个数据库独立初始化表结构schema和数据库database。
- 支持无数据源启动,支持懒加载数据源(需要的时候再创建连接)。
- 支持 自定义注解 ,需继承DS(3.2.0+)。
- 提供并简化对Druid,HikariCp,BeeCp,Dbcp2的快速集成。
- 提供对Mybatis-Plus,Quartz,ShardingJdbc,P6sy,Jndi等组件的集成方案。
- 提供 自定义数据源来源 方案(如全从数据库加载)。
- 提供项目启动后 动态增加移除数据源 方案。
- 提供Mybatis环境下的 纯读写分离 方案。
- 提供使用 spel动态参数 解析数据源方案。内置spel,session,header,支持自定义。
- 支持 多层数据源嵌套切换 。(ServiceA >>> ServiceB >>> ServiceC)。
- 提供 **基于seata的分布式事务方案。
- 提供 本地多数据源事务方案
二、使用方法
第1步:引入
dynamic-datasource-spring-boot-starter或者
dynamic-datasource-spring-boot3-starter
<!-- 适合 SpringBoot 1.5.x + 2.x 版本 -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>dynamic-datasource-spring-boot-starter</artifactId>
<version>${version}</version>
</dependency>
<!-- 适合 SpringBoot 3.x 版本 -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>dynamic-datasource-spring-boot3-starter</artifactId>
<version>${version}</version>
</dependency>
第2步:配置数据源
spring:
datasource:
dynamic:
enabled: true #启用动态数据源,默认true
primary: master #设置默认的数据源或者数据源组,默认值即为master
strict: false #严格匹配数据源,默认false. true未匹配到指定数据源时抛异常,false使用默认数据源
grace-destroy: false #是否优雅关闭数据源,默认为false,设置为true时,关闭数据源时如果数据源中还存在活跃连接,至多等待10s后强制关闭
datasource:
master:
url: jdbc:mysql://xx.xx.xx.xx:3306/dynamic
username: root
password: 123456
driver-class-name: com.mysql.jdbc.Driver # 3.2.0开始支持SPI可省略此配置
slave_1:
url: jdbc:mysql://xx.xx.xx.xx:3307/dynamic
username: root
password: 123456
driver-class-name: com.mysql.jdbc.Driver
slave_2:
url: ENC(xxxxx) # 内置加密,使用请查看详细文档
username: ENC(xxxxx)
password: ENC(xxxxx)
driver-class-name: com.mysql.jdbc.Driver
#......省略
#以上会配置一个默认库master,一个组slave下有两个子库slave_1,slave_2
多主多从:
spring:
datasource:
dynamic:
datasource:
master_1:
master_2:
slave_1:
slave_2:
slave_3:
纯粹多库:
spring:
datasource:
dynamic:
datasource:
mysql:
oracle:
sqlserver:
postgresql:
h2:
混合配置:
spring:
datasource:
dynamic:
datasource:
master:
slave_1:
slave_2:
oracle_1:
oracle_2:
第3步:使用 @DS 切换数据源
@DS 可以注解在方法上或类上,同时存在就近原则 方法上注解 优先于 类上注解。
@Service
@DS("slave")
public class UserServiceImpl implements UserService {
@Autowired
private JdbcTemplate jdbcTemplate;
public List selectAll() {
return jdbcTemplate.queryForList("select * from user");
}
@Override
@DS("slave_1")
public List selectByCondition() {
return jdbcTemplate.queryForList("select * from user where age >10");
}
}
三、案例:dynamic-datasource+mybatis使用方法
maven引入
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>dynamic-datasource-spring-boot-starter</artifactId>
<version>3.1.0</version>
</dependency>
<dependency>
<groupId>tk.mybatis</groupId>
<artifactId>mapper-spring-boot-starter</artifactId>
<version>2.1.5</version>
</dependency>
配置好数据源
spring:
datasource:
dynamic:
primary: master1
strict: false
datasource:
master1:
url: jdbc:mysql://127.0.0.1:3306/master1?useUnicode=true&characterEncoding=UTF-8&useSSL=false&autoReconnect=true&failOverReadOnly=false&serverTimezone=GMT%2B8
username: root
password: andrew
driver-class-name: com.mysql.cj.jdbc.Driver
master2:
url: jdbc:mysql://127.0.0.1:3306/master2?useUnicode=true&characterEncoding=UTF-8&useSSL=false&autoReconnect=true&failOverReadOnly=false&serverTimezone=GMT%2B8
username: root
password: andrew
driver-class-name: com.mysql.cj.jdbc.Driver
master3:
url: jdbc:oracle:thin:@10.132.212.63:1688:TESTDB
username: flx
password: flx202108
driver-class-name: oracle.jdbc.OracleDriver
logging:
level:
com.xkcoding: debug
com.xkcoding.orm.mybatis.mapper: trace
server:
port: 8080
# servlet:
# context-path: /demo
mybatis:
type-aliases-package: com.orm.mybatis.dsannotation.entity
mapper-locations: classpath:mapper/*/*.xml
configuration:
map-underscore-to-camel-case: true
service层
里面在想要切换数据源的方法上加上@DS注解就行了,也可以加在整个service层上,方法上的注解优先于类上注解
@Service
public class UserServiceImpl {
@Resource
private UserMapper1 userMapper1;
@Resource
private UserMapper2 userMapper2;
@Resource
private AsusPoInfoMapper3 asusPoInfoMapper3;
@DS("master1")
public List<User> findAllUser(){
List<User> list = userMapper1.selectAllUser();
return list;
}
@DS("master2")
public List<User> findAllUser1(){
List<User> list = userMapper2.selectAllUser();
return list;
}
public User findUserById(Long id){
return userMapper1.selectUserById(id);
}
@Transactional //与dynamic不同的是,这两个注解可以一起使用会先切换数据源再事务
@DS("master1") //与dynamic不同的是,这两个注解可以一起使用会先切换数据源再事务
public void insertUser1(){
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String date = simpleDateFormat.format(new Date());
String UUID = java.util.UUID.randomUUID().toString().substring(0,5);
User user = User.builder().email("andrew@qq.com"+UUID).name("andrew"+UUID).password("123456"+UUID).phoneNumber("123"+UUID)
.lastUpdateTime(date).createTime(date).status(0).salt("password"+UUID).build();
userMapper1.saveUser(user);
}
@Transactional
@DS("master2")
public void insertUser2(){
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String date = simpleDateFormat.format(new Date());
String UUID = java.util.UUID.randomUUID().toString().substring(0,5);
User user = User.builder().email("andrew@qq.com"+UUID).name("andrew"+UUID).password("123456"+UUID).phoneNumber("123"+UUID)
.lastUpdateTime(date).createTime(date).status(0).salt("password"+UUID).build();
userMapper2.saveUser(user);
}
public void testTransitional() {
((UserServiceImpl)AopContext.currentProxy()).insertUser1();
((UserServiceImpl)AopContext.currentProxy()).insertUser2();
((UserServiceImpl)AopContext.currentProxy()).insertOracle();
}
@DS("master3")
public List<AsusPoInfo> selectOracle(){
return asusPoInfoMapper3.selectAllAsusPoInfo();
}
@DS("master3")//与dynamic不同的是,这两个注解可以一起使用会先切换数据源再事务
@Transactional
public void insertOracle(){
AsusPoInfo asusPoInfo = AsusPoInfo.builder().id(java.util.UUID.randomUUID().toString().substring(0,20))
.woNo("andrew").po("123456").poLine("poline").cPo("cpo123456").shipType("Direct").build();
asusPoInfoMapper3.insertAsusPoInfo(asusPoInfo);
}
}
测试多数据源回滚
package com.orm.mybatis.dsannotation;
import com.orm.mybatis.dsannotation.entity.AsusPoInfo;
import com.orm.mybatis.dsannotation.entity.User;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import com.orm.mybatis.dsannotation.serviceImpl.UserServiceImpl;
import javax.annotation.Resource;
import java.util.List;
@SpringBootTest
class SpringbootMybatisDsannotationDatasourceApplicationTests {
//事务测试
@Resource
private UserServiceImpl userService;
@Test
void contextLoads1() {
List<AsusPoInfo> list = userService.selectOracle();
System.out.println(list);
}
@Test
void contextLoads2() {
List<User> list = userService.findAllUser();
System.out.println(list);
}
@Test
void contextLoads3() {
List<User> list = userService.findAllUser();
List<User> list1 = userService.findAllUser1();
List<AsusPoInfo> list2 = userService.selectOracle();
list.addAll(list1);
System.out.println(list);
System.out.println(list2);
}
@Test
void contextLoads4() {
userService.testTransitional();
}
}
切换数据源成功,而且事务能回滚,但如果是多数据源事务,只能回滚报错的数据源的事务。
四、方案的权衡
- 静态多数据源方案优势在于配置简单并且对业务代码的入侵性极小,缺点也显而易见:我们需要在系统中占用一些资源,而这些资源并不是一直需要,一定程度上会造成资源的浪费。如果你需要在一段业务代码中同时使用多个数据源的数据又要去考虑操作的原子性(事务)可以用spring的jta实现事务,那么这种方案无疑会适合你。
- (aop和dynamic)动态数据源(AbstractRoutingDataSource)方案配置上看起来配置会稍微复杂一些,但是很好的符合了“即拿即用,即用即还”的设计原则,我们把多个数据源看成了一个池子,然后进行消费。它的缺点正如上文所暴露的那样:我们往往需要在事务的需求下做出妥协。而且由于需要切换环境上下文,在高并发量的系统上进行资源竞争时容易发生死锁等活跃性问题。我们常用它来进行数据库的“读写分离”,不需要在一段业务中同时操作多个数据源。这种动态形式并不能用spring的jta实现,而且其他实现方式(seata等)虽然可以实现,但配置复杂且实用度不高。
- 如果需要使用事务,一定记得使用分布式事务进行Spring自带事务管理的替换,否则将无法进行一致性控制。
相关推荐
- Java面试宝典之问答系列(java面试回答)
-
以下内容,由兆隆IT云学院就业部根据多年成功就业服务经验提供:1.写出从数据库表Custom中查询No、Name、Num1、Num2并将Name以姓名显示、计算出的和以总和显示的SQL。SELECT...
- ADG (Active Data Guard) 数据容灾架构下,如何配置 Druid 连接池?
-
如上图的数据容灾架构下,上层应用如果使用Druid连接池,应该如何配置,才能在数据库集群节点切换甚至主备数据中心站点切换的情况下,上层应用不需要变动(无需修改配置也无需重启);即数据库节点宕机/...
- SpringBoot多数据源dynamic-datasource快速入门
-
一、简介dynamic-datasourc是一个基于SpringBoot的快速集成多数据源的启动器,其主要特性如下:支持数据源分组,适用于多种场景纯粹多库读写分离一主多从混合模式。支持...
- SpringBoot项目快速开发框架JeecgBoot——项目简介及系统架构!
-
项目简介及系统架构JeecgBoot是一款基于SpringBoot的开发平台,它采用前后端分离架构,集成的框架有SpringBoot2.x、SpringCloud、AntDesignof...
- 常见文件系统格式有哪些(文件系统类型有哪几种)
-
PART.01常见文件系统格式有哪些常见的文件系统格式有很多,通常根据使用场景(Windows、Linux、macOS、移动设备、U盘、硬盘等)有所不同。以下是一些主流和常见的文件系统格式及其特点:一...
- Oracle MySQL Operator部署集群(oracle mysql group by)
-
以下是使用OracleMySQLOperator部署MySQL集群的完整流程及关键注意事项:一、部署前准备安装MySQLOperator通过Helm安装Operator到Ku...
- LibreOffice加入"转向Linux"运动
-
LibreOffice项目正准备削减部分Windows支持,并鼓励用户切换到Linux系统。自Oracle放弃OpenOffice后,支持和指导LibreOffice开发的文档基金会对未来有着明确的观...
- Oracle Linux 10发布:UEK 8.1、后量子加密、增强开发工具等
-
IT之家6月28日消息,科技媒体linuxiac昨日(6月27日)发布博文,报道称OracleLinux10正式发布,完全二进制兼容(binarycompatibility...
- 【mykit-data】 数据库同步工具(数据库同步工具 开源)
-
项目介绍支持插件化、可视化的数据异构中间件,支持的数据异构方式如下MySQL<——>MySQL(增量、全量)MySQL<——>Oracle(增量、全量)Oracle...
- oracle关于xml的解析(oracle读取xml节点的属性值)
-
有时需要在存储过程中处理xml,oracle提供了相应的函数来进行处理,xmltype以及相关的函数。废话少说,上代码:selectxmltype(SIConfirmOutput).extract...
- 如何利用DBSync实现数据库同步(通过dblink同步数据库)
-
DBSync是一款通用型的数据库同步软件,能侦测数据表之间的差异,能实时同步差异数据,从而使双方始终保持一致。支持各种数据库,支持异构同步、增量同步,且提供永久免费版。本文介绍其功能特点及大致用法,供...
- MYSQL存储引擎InnoDB(八十):InnoDB静态数据加密
-
InnoDB支持独立表空间、通用表空间、mysql系统表空间、重做日志和撤消日志的静态数据加密。从MySQL8.0.16开始,还支持为模式和通用表空间设置加密默认值,这允许DBA控制在这些模...
- JDK高版本特性总结与ZGC实践(jdk高版本兼容低版本吗)
-
美团信息安全技术团队核心服务升级JDK17后,性能与稳定性大幅提升,机器成本降低了10%。高版本JDK与ZGC技术令人惊艳,且JavaAISDK最低支持JDK17。本文总结了JDK17的主要...
- 4 种 MySQL 同步 ES 方案,yyds!(两个mysql数据库自动同步的方法)
-
本文会先讲述数据同步的4种方案,并给出常用数据迁移工具,干货满满!不BB,上文章目录:1.前言在实际项目开发中,我们经常将MySQL作为业务数据库,ES作为查询数据库,用来实现读写分离,...
- 计算机Java培训课程包含哪些内容?其实就这六大块
-
不知不觉秋天已至,如果你还处于就业迷茫期,不如来学习Java。对于非科班小白来说,Java培训会更适合你。提前了解下计算机Java培训课程内容,会有助于你后续学习。下面,我就从六个部分为大家详细介绍...
你 发表评论:
欢迎- 一周热门
- 最近发表
-
- Java面试宝典之问答系列(java面试回答)
- ADG (Active Data Guard) 数据容灾架构下,如何配置 Druid 连接池?
- SpringBoot多数据源dynamic-datasource快速入门
- SpringBoot项目快速开发框架JeecgBoot——项目简介及系统架构!
- 常见文件系统格式有哪些(文件系统类型有哪几种)
- Oracle MySQL Operator部署集群(oracle mysql group by)
- LibreOffice加入"转向Linux"运动
- Oracle Linux 10发布:UEK 8.1、后量子加密、增强开发工具等
- 【mykit-data】 数据库同步工具(数据库同步工具 开源)
- oracle关于xml的解析(oracle读取xml节点的属性值)
- 标签列表
-
- oracle位图索引 (74)
- oracle批量插入数据 (65)
- oracle事务隔离级别 (59)
- oracle 空为0 (51)
- oracle主从同步 (55)
- oracle 乐观锁 (51)
- redis 命令 (78)
- php redis (88)
- redis 存储 (66)
- redis 锁 (69)
- 启动 redis (66)
- redis 时间 (56)
- redis 删除 (67)
- redis内存 (57)
- redis并发 (52)
- redis 主从 (69)
- redis 订阅 (51)
- redis 登录 (54)
- redis 面试 (58)
- 阿里 redis (59)
- redis 搭建 (53)
- redis的缓存 (55)
- lua redis (58)
- redis 连接池 (61)
- redis 限流 (51)