SpringBoot 手动实现动态切换数据源 DynamicSource (中)
大家好,我是此林。
SpringBoot 手动实现动态切换数据源 DynamicSource (上)-CSDN博客
在上一篇博客中,我带大家手动实现了一个简易版的数据源切换实现,方便大家理解数据源切换的原理。今天我们来介绍一个开源的数据源切换框架,是baomidou 旗下和 Mybatis-plus 同级的开源框架:dynamic-datasource-spring-boot-starter。
1. 简介
dynamic-datasource-spring-boot-starter 是一个基于springboot的快速集成多数据源的启动器。
其支持 Jdk 1.7+, SpringBoot 1.5.x 2.x.x 3.x.x。
JPA用户不建议使用,JPA自带事务,无法连续切库。
2. 使用
下面基于SpringBoot2 做演示。
1.pom.xml
<dependency><groupId>com.baomidou</groupId><artifactId>dynamic-datasource-spring-boot-starter</artifactId><version>4.3.1</version>
</dependency>
2.application.yml
spring:datasource:dynamic:primary: master #设置默认的数据源或者数据源组,默认值即为masterstrict: false #严格匹配数据源,默认false. true未匹配到指定数据源时抛异常,false使用默认数据源datasource:master:url: jdbc:mysql://192.168.183.128:3306/userusername: rootpassword: 123456slave_1:url: jdbc:mysql://192.168.183.128:3307/userusername: rootpassword: 123456slave_2:url: jdbc:mysql://192.168.183.128:3308/userusername: rootpassword: 123456
参数说明:
以上会配置一个默认库master,一个组slave下有两个子库slave_1,slave_2
后续我们会使用AOP注解的方式指定数据源。
例如:@DS("master")、@DS("slave")
- 配置文件所有以下划线
_分割的数据源 首部 即为组的名称,相同组名称的数据源会放在一个组下。 - 切换数据源可以是组名,也可以是具体数据源名称。组名则切换时采用负载均衡算法切换。
例如:当我们使用@DS("slave")时,指定了组名 “slave”,那么它会采用负载均衡算法自动切换数据源。
因为我们后续希望实现Mysql主从读写分离,所有写操作走master数据库,所有读操作走slave从数据库。
3. 使用 @DS 切换数据源。
@Service
public class UserServiceImpl implements UserService {@Autowiredprivate UserMapper userMapper;@Overridepublic void insert(User user) {userMapper.insert(user);}@Override@DS("slave_1")public List<User> selectAll() {userMapper.selectAll();}@Override@DS("slave")public User selectById(Integer id) {return userMapper.selectById(id);}
}
说明:
insert() 方法没有加@DS,默认使用master数据库。
selectAll() 方法指定使用数据源slave_1
selectById() 使用slave组,自动负载均衡查询。
注:@DS 可以注解在方法上或类上,同时存在就近原则 方法上注解 优先于 类上注解。
若要实现Mysql主从自动复制,还需要配置mysql主从复制,详情参考博客:
ShardingSphere5:Mysql主从集群搭建、读写分离_shardingsphere mysql读写分离-CSDN博客
其中SpringBoot配置 ShardingSphere5 这一块不用管,Mysql主从集群搭建是不变的。
4.其他实现

3. 底层原理
1. SpringBoot自动配置
我们找到 DynamicDataSourceAutoConfiguration.class。 这是框架的自动配置类。

这一段是从我们配置的application.yml 读取并设置相关属性,也就是我们配置的数据源信息。
具体的话,是赋值给 DynamicRoutingDataSource 这个对象。
2. 扫描@DS注解
这是 DynamicDataSourceAnnotationInterceptor 的 invoke 方法,典型的AOP。

在所有加了@DS的方法上,
1. 当执行目标方法的时候,会先获取到@DS("XXX")中数据源的名称,dsKey。
2. 然后再把dsKey 存到ThreadLocal中,也就是图中的DynamicDataSourceContextHolder。
3. 最后再开始执行目标方法。
3. DynamicRoutingDataSource
回到我们之前自动配置里说的 DynamicRoutingDataSource

观察 DynamicRoutingDataSource 的继承关系链,发现它实现了Spring的 DataSource 和 InitializingBean 接口。
这和我们上一篇博客手动实现数据源切换的思路是一样的。
在 DynamicRoutingDataSource 里,determineDataSource 从 ThreadLocal 里 获取到指定数据源名称

最后通过名称返回对应的DataSource数据源。

对比上一篇博客,
SpringBoot 手动实现动态切换数据源 DynamicSource (上)-CSDN博客
其实思路大差不差,只不过 dynamic-datasource-spring-boot-starter 更加完善,增加了AOP注解功能。
4. 无注解切换数据源
1. 自定义切面,结合 DynamicDatasourceNamedInterceptor ,对于所有以 select 方法开头的,设置使用 slave 数据源, 对于add、update、delete 开头的使用 master 数据源。
2. 自定义 Mybatis 拦截器,对于所有的写操作使用 master 数据源,所有读操作使用 slave 数据源。(即:把数据源标识写入 DynamicDataSourceContextHolder 中)。
3. 其他场景:SaaS多租户系统下,每个租户使用独立的数据库,那么可以要求前端携带请求头 “dsKey”。配置自定义拦截器,拦截请求,把dsKey 写入 DynamicDataSourceContextHolder。
今天的分享就到这里。
我是此林,关注我吧,带你看不一样的世界!
相关文章:
SpringBoot 手动实现动态切换数据源 DynamicSource (中)
大家好,我是此林。 SpringBoot 手动实现动态切换数据源 DynamicSource (上)-CSDN博客 在上一篇博客中,我带大家手动实现了一个简易版的数据源切换实现,方便大家理解数据源切换的原理。今天我们来介绍一个开源的数据源…...
y3编辑器教学5:触发器2 案例演示
文章目录 一、探索1.1 ECA1.1.1 ECA的定义1.1.2 使用触发器实现瞬间移动效果 1.2 变量1.2.1 什么是变量1.2.2 使用变量存储碎片收集数量并展现 1.3 if语句(魔法效果挂接)1.3.1 地形设置1.3.2 编写能量灌注逻辑1.3.3 编写能量灌注后,实现传送逻…...
数值分析——插值法(二)
文章目录 前言一、Hermite插值1.两点三次Hermite插值2.两点三次Hermite插值的推广3.非标准型Hermite插值 二、三次样条插值1.概念2.三弯矩方程 前言 之前写过Lagrange插值与Newton插值法的内容,这里介绍一些其他的插值方法,顺便复习数值分析. 一、Hermi…...
杨振宁大学物理视频中黄色的字,c#写程序去掉
先看一下效果:(还有改进的余地) 写了个程序消除杨振宁大学物理中黄色的字 我的方法是笨方法,也比较刻板。 1,首先想到,把屏幕打印下来。c#提供了这样一个函数: Bitmap bmp new Bitmap(640, 48…...
uni-app 设置缓存过期时间【跨端开发系列】
🔗 uniapp 跨端开发系列文章:🎀🎀🎀 uni-app 组成和跨端原理 【跨端开发系列】 uni-app 各端差异注意事项 【跨端开发系列】uni-app 离线本地存储方案 【跨端开发系列】uni-app UI库、框架、组件选型指南 【跨端开…...
微信小程序base64图片与临时路径互相转换
1、base64图片转临时路径 /*** 将base64图片转临时路径* param {*} dataurl* param {*} filename* returns*/base64ImgToFile(dataurl, filename "file") {const base64 dataurl; // base64码const time new Date().getTime();const imgPath wx.env.USER_DATA_P…...
蓝桥杯刷题——day2
蓝桥杯刷题——day2 题目一题干题目解析代码 题目二题干解题思路代码 题目一 题干 三步问题。有个小孩正在上楼梯,楼梯有n阶台阶,小孩一次可以上1阶、2阶或3阶。实现一种方法,计算小孩有多少种上楼梯的方式。结果可能很大,你需要…...
5.删除链表的倒数第N个节点
19.删除链表的倒数第N个节点 题目: 19. 删除链表的倒数第 N 个结点 - 力扣(LeetCode) 分析: 要删除倒数第几个节点,那么我们需要怎么做呢?我们需要定义两个指针,快指针和慢指针,…...
自己总结:selenium高阶知识
全篇大概10000字(含代码),建议阅读时间30min 一、等待机制 如果有一些内容是通过Ajax加载的内容,那就需要等待内容加载完毕才能进行下一步操作。 为了避免人为操作等待,会遇到的问题, selenium将等待转换…...
前端怎么预览pdf
1.背景 后台返回了一个在线的pdf地址,需要我这边去做一个pdf的预览(需求1),并且支持配置是否可以下载(需求2),需要在当前页就能预览(需求3)。之前我写过一篇预览pdf的文…...
activemq 的安装部署
下载 https://activemq.apache.org/components/classic/download/# 在/opt目录下载 wget https://dlcdn.apache.org//activemq/5.18.6/apache-activemq-5.18.6-bin.tar.gz解压 tar -zxvf apache-activemq-5.18.6-bin.tar.gz配置java环境 vim /opt/apache-activemq-5.18.6/b…...
【H3CNE邓方鸣】配置链路聚合+2024.12.11
文章目录 链路聚合作用负载分担分类静态聚合动态聚合 链路聚合作用 定义:把连接到统一交换机上的多个物理端口捆绑为一个逻辑端口 增加链路带宽:聚合组内只要还有物理端口存活,链路就不会中断 提供链路可靠性:避免了STP计算&…...
C语言 学习 日志 递归函数 2024/12/12
C语言 学习 日志 递归函数 介绍: 初始调用:递归函数被首次调用。递归调用:递归函数在其定义中调用自身,创建新的栈帧。基本情况检查:每次递归调用时,检查是否满足基本情况。如果满足,返回结果并开始回溯。…...
【Ubuntu】使用ip link工具创建虚拟局域网并配置?
🦋🦋🦋如何使用ip link工具创建虚拟局域网? sudo ip link add link enx888bd66b7000 name enx.120 type vlan id 120 上述命令使用ip link工具在Linux系统中创建了一个新的虚拟局域网(VLAN)接口,…...
flink sink kafka的事务提交现象猜想
现象 查看flink源码时 sink kafka有事务提交机制,查看源码发现是使用两阶段提交策略,而事务提交是checkpoint完成后才执行,那么如果checkpoint设置间隔时间比较长时,事务未提交之前,后端应该消费不到数据,…...
网络原理03
回顾 应用层:应用程序,数据具体如何使用 传输层:关注起点和终点 网络层:关注路径规划 数据链路层:关注相邻节点的转发 物理层:硬件设备 应用层 应用程序 在应用层,很多时候,…...
每天40分玩转Django:简介和环境搭建
Django简介和环境搭建 一、课程概述 学习项目具体内容预计用时Django概念Django框架介绍、MVC/MTV模式、Django特点60分钟环境搭建Python安装、pip配置、Django安装、IDE选择45分钟创建项目项目结构、基本配置、运行测试75分钟实战练习创建个人博客项目框架60分钟 二、Djang…...
【蓝桥杯最新板】蓝桥杯嵌入式液晶上实现电子时钟
这几年蓝桥杯比赛比较适合学生技能学习,考虑板子功能,提出完成的任务。 要求在液晶完成如下图效果: 主要是实现液晶显示时钟和数字时钟,具体样式可以依据实际情况微调。 实现过程: 1.需要画圆(外圆、内圆…...
【机器学习】基础知识:拟合度(Goodness of Fit)
拟合度概念及意义 拟合度(Goodness of Fit)是衡量统计模型对数据解释能力的指标,用于评价模型对观测数据的拟合效果。在回归分析、分类模型或其他预测模型中,拟合度是模型性能的重要衡量标准。 1. 拟合度的作用 拟合度的主要作用…...
使用Jackson库在Java应用程序中将Map对象转换为JSON数组字符串,以及反向操作
在现代Java应用程序中,特别是使用RESTful Web服务时,经常需要将Java对象转换为JSON格式,反之亦然。 当表示如用户管理系统中的用户列表这样的数据结构时,将Map转换为JSON数组字符串变得非常有用。在这个指南中,我们将…...
生成xcframework
打包 XCFramework 的方法 XCFramework 是苹果推出的一种多平台二进制分发格式,可以包含多个架构和平台的代码。打包 XCFramework 通常用于分发库或框架。 使用 Xcode 命令行工具打包 通过 xcodebuild 命令可以打包 XCFramework。确保项目已经配置好需要支持的平台…...
Lombok 的 @Data 注解失效,未生成 getter/setter 方法引发的HTTP 406 错误
HTTP 状态码 406 (Not Acceptable) 和 500 (Internal Server Error) 是两类完全不同的错误,它们的含义、原因和解决方法都有显著区别。以下是详细对比: 1. HTTP 406 (Not Acceptable) 含义: 客户端请求的内容类型与服务器支持的内容类型不匹…...
利用ngx_stream_return_module构建简易 TCP/UDP 响应网关
一、模块概述 ngx_stream_return_module 提供了一个极简的指令: return <value>;在收到客户端连接后,立即将 <value> 写回并关闭连接。<value> 支持内嵌文本和内置变量(如 $time_iso8601、$remote_addr 等)&a…...
React hook之useRef
React useRef 详解 useRef 是 React 提供的一个 Hook,用于在函数组件中创建可变的引用对象。它在 React 开发中有多种重要用途,下面我将全面详细地介绍它的特性和用法。 基本概念 1. 创建 ref const refContainer useRef(initialValue);initialValu…...
Qt Widget类解析与代码注释
#include "widget.h" #include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget) {ui->setupUi(this); }Widget::~Widget() {delete ui; }//解释这串代码,写上注释 当然可以!这段代码是 Qt …...
大数据零基础学习day1之环境准备和大数据初步理解
学习大数据会使用到多台Linux服务器。 一、环境准备 1、VMware 基于VMware构建Linux虚拟机 是大数据从业者或者IT从业者的必备技能之一也是成本低廉的方案 所以VMware虚拟机方案是必须要学习的。 (1)设置网关 打开VMware虚拟机,点击编辑…...
Go 语言接口详解
Go 语言接口详解 核心概念 接口定义 在 Go 语言中,接口是一种抽象类型,它定义了一组方法的集合: // 定义接口 type Shape interface {Area() float64Perimeter() float64 } 接口实现 Go 接口的实现是隐式的: // 矩形结构体…...
多模态商品数据接口:融合图像、语音与文字的下一代商品详情体验
一、多模态商品数据接口的技术架构 (一)多模态数据融合引擎 跨模态语义对齐 通过Transformer架构实现图像、语音、文字的语义关联。例如,当用户上传一张“蓝色连衣裙”的图片时,接口可自动提取图像中的颜色(RGB值&…...
Nuxt.js 中的路由配置详解
Nuxt.js 通过其内置的路由系统简化了应用的路由配置,使得开发者可以轻松地管理页面导航和 URL 结构。路由配置主要涉及页面组件的组织、动态路由的设置以及路由元信息的配置。 自动路由生成 Nuxt.js 会根据 pages 目录下的文件结构自动生成路由配置。每个文件都会对…...
生成 Git SSH 证书
🔑 1. 生成 SSH 密钥对 在终端(Windows 使用 Git Bash,Mac/Linux 使用 Terminal)执行命令: ssh-keygen -t rsa -b 4096 -C "your_emailexample.com" 参数说明: -t rsa&#x…...
