SpringBoot轻松实现多数据源切换
一.需求背景
项目需要实现在多个数据源之间读写数据,例如在 A 数据源和 B 数据源读取数据,然后在 C 数据源写入数据 或者 部分业务数据从 A 数据源中读取、部分从B数据源中读取诸如此类需求。本文将简单模拟在SpringBoot项目中实现不同数据源之间读取数据。
二.技术概述
dynamic-datasource
是一个开源的 SpringBoot 多数据源启动器,提供了丰富的功能,使用者只需完成基本的数据源配置,配合使用@DS
注解即可轻松实现多数据源之间的切换。其支持 Jdk 1.7+, SpringBoot 1.5.x 2.x.x 3.x.x。JPA用户不建议使用,JPA自带事务,无法连续切库。
以下特性和约定摘录自官方文档:dynamic-datasource
-
特性
-
支持 数据源分组 ,适用于多种场景 纯粹多库 读写分离 一主多从 混合模式。
-
支持数据库敏感配置信息 加密(可自定义) 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的分布式事务方案 。
-
提供 本地多数据源事务方案。
-
-
约定
- 本框架只做 切换数据源 这件核心的事情,并不限制你的具体操作,切换了数据源可以做任何CRUD。
- 配置文件所有以下划线
_
分割的数据源 首部 即为组的名称,相同组名称的数据源会放在一个组下。 - 切换数据源可以是组名,也可以是具体数据源名称。组名则切换时采用负载均衡算法切换。、
- 默认的数据源名称为 master ,你可以通过
spring.datasource.dynamic.primary
修改。 - 代码块里主动切换 > 方法上的注解优 > 类上注解(就近原则)
- DS支持继承抽象类上的DS,支持继承接口上的DS。
注:官网文档只有基础篇可免费查阅,其他内容查阅需付费29.9¥
,因此如果基础篇所讲解功能无法满足需求(业务场景比较复杂)且不愿付费请勿使用本框架!
三.编码实现
业务说明:从A数据源查询出学生数据同时从B数据源查询出教师数据。
技术选型:SpringBoot 2.7.6 + MyBatis-Plus 3.5.4 + MySQL 8.0
1)引入Maven坐标
<dependency><groupId>com.baomidou</groupId><artifactId>dynamic-datasource-spring-boot-starter</artifactId><version>3.5.2</version>
</dependency>
2)创建模拟数据库表,
# A 数据源
create DATABASE testA;
use testA;
CREATE TABLE student(
id int,
username VARCHAR(12)
);# B 数据源
create DATABASE testB;
use testB;
CREATE TABLE teacher(
id int,
username VARCHAR(12)
);
3)在yml文件中配置数据源
spring:datasource:dynamic:primary: testA #设置默认的数据源或者数据源组,默认值即为masterstrict: false #严格匹配数据源,默认false. true未匹配到指定数据源时抛异常,false使用默认数据源datasource:testA:driver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://localhost:3306/testAusername: rootpassword: roottestB:driver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://localhost:3306/testBusername: rootpassword: root
4)可以用MyBatis-X插件快速生成项目骨架。
5)使用@DS
注解在mapper文件中指定数据源。注意,数据源名称需要与yml配置中的一致。
// 指定学生表的数据源为testA
@DS("testA")
public interface StudentMapper extends BaseMapper<Student> {
}// 指定教师表的数据源为testB
@DS("testB")
public interface TeacherMapper extends BaseMapper<Teacher> {
}
5)创建测试类进行测试
@SpringBootTest
public class MultipleDataSourceTest {@Resourceprivate StudentService studentService;@Resourceprivate TeacherService teacherService;@Testvoid testSelect() {System.out.println("====== 学生表数据 ======");for (Student student : studentService.list()) {System.out.println(">>> " + student);}System.out.println("====== 教师表数据 ======");for (Teacher teacher : teacherService.list()) {System.out.println(">>> " + teacher);}}
}
6)相关执行日志查看,可以通过日志看到已经成功加载两个数据源并且指定默认数据源为[testA],同时我们所查询的数据也能正常出来。
INFO 312 --- [main] com.zaxxer.hikari.HikariDataSource: testA - Starting...
INFO 312 --- [main] com.zaxxer.hikari.HikariDataSource: testA - Start completed.
INFO 312 --- [main] com.zaxxer.hikari.HikariDataSource: testB - Starting...
INFO 312 --- [main] com.zaxxer.hikari.HikariDataSource: testB - Start completed.
INFO 312 --- [main] c.b.d.d.DynamicRoutingDataSource: dynamic-datasource - add a datasource named [testB] success
INFO 312 --- [main] c.b.d.d.DynamicRoutingDataSource: dynamic-datasource - add a datasource named [testA] success
INFO 312 --- [main] c.b.d.d.DynamicRoutingDataSource: dynamic-datasource initial loaded [2] datasource,primary datasource named [testA]
====== 学生表数据 ======
>>> Student(id=1, username=学生1)
>>> Student(id=2, username=学生2)
>>> Student(id=3, username=学生3)
>>> Student(id=4, username=学生4)
>>> Student(id=5, username=学生5)
====== 教师表数据 ======
>>> Teacher(id=1, username=教师1)
>>> Teacher(id=2, username=教师2)
>>> Teacher(id=3, username=教师3)
>>> Teacher(id=4, username=教师4)
>>> Teacher(id=5, username=教师5)
INFO 312 --- [ionShutdownHook] c.b.d.d.DynamicRoutingDataSource: dynamic-datasource start closing ....
INFO 312 --- [ionShutdownHook] com.zaxxer.hikari.HikariDataSource: testB - Shutdown initiated...
INFO 312 --- [ionShutdownHook] com.zaxxer.hikari.HikariDataSource: testB - Shutdown completed.
INFO 312 --- [ionShutdownHook] com.zaxxer.hikari.HikariDataSource: testA - Shutdown initiated...
INFO 312 --- [ionShutdownHook] com.zaxxer.hikari.HikariDataSource: testA - Shutdown completed.
INFO 312 --- [ionShutdownHook] c.b.d.d.DynamicRoutingDataSource: dynamic-datasource all closed success,bye
四.补充说明
以上示例可以完成基本的多数据源切换需求,对于一些复杂场景,由于官方文档付费,请根据需要使用。例如:
-
在需要切换数据源的代码最外层加上了事务注解
@Transactional
将会导致数据源切换失效,上述代码加上注解运行将报错(由于无法切换数据源,将使用默认数据源,如果默认数据源中没有对应的表将报错),在网上检索发现通过添加官方提供的@DSTransactional
即可实现事务下数据源切换:@Test@Transactionalvoid testSelect() {System.out.println("====== 学生表数据 ======");for (Student student : studentService.list()) {System.out.println(">>> " + student);}System.out.println("====== 教师表数据 ======");for (Teacher teacher : teacherService.list()) {System.out.println(">>> " + teacher);}}
-
在多线程情况下,如果使用编码方式实现数据源切换也将导致问题,需要进行一些其他处理。
最后,补充说明想表达的由于官网文档是付费的,不付费的话许多问题只能搜索寻找解决方法比较麻烦,因此,请根据自身业务情况选择使用本框架或其他框架。
相关文章:

SpringBoot轻松实现多数据源切换
一.需求背景 项目需要实现在多个数据源之间读写数据,例如在 A 数据源和 B 数据源读取数据,然后在 C 数据源写入数据 或者 部分业务数据从 A 数据源中读取、部分从B数据源中读取诸如此类需求。本文将简单模拟在SpringBoot项目中实现不同数据源之间读取数…...
Qt 5 当类的信号函数和成员函数,函数名相同时,连接信号和槽的写法。
前言:因为项目需要,软件要在windows7上运行,然后项目目前是qt6写的,然后搜索资料,需要qt5.15.2或之前的版本才能在win7上运行,于是下载了qt5.15.2,将qt6的代码在qt5编译时,很多错误&…...
Vuex 介绍及示例
Vuex 是 Vue.js 的一个状态管理模式和库,用于管理 Vue 应用中的全局状态。它是专门为 Vue.js 应用设计的,充分利用了 Vue 的细粒度响应系统来高效地更新状态。以下是对 Vuex 的一些介绍和它的基本使用方法: 主要概念 State(状态&…...
【elementui】记录如何重命名elementui组件名称
在main.js中,就是引入elementui的文件中 import ElementUI from element-ui import { Tree } from element-uiVue.use(ElementUI) Vue.component(el-tree-rename, Tree)...
MySQL面试篇章—MySQL锁机制
文章目录 MySQL的锁机制表级锁 & 行级锁排它锁和共享锁InnoDB行级锁行级锁间隙锁意向共享锁和意向排它锁 InnoDB表级锁死锁锁的优化建议MVCC多版本并发控制MyISAM表级锁表级锁并发插入优化锁调度优化 MySQL的锁机制 表级锁 & 行级锁 表级锁:对整张表加锁&…...

OAK相机支持的图像传感器有哪些?
相机支持的传感器 在 RVC2 上,固件必须具有传感器配置才能支持给定的相机传感器。目前,我们支持下面列出的相机传感器的开箱即用(固件中)传感器配置。 名称 分辨率 传感器类型 尺寸 最大 帧率 IMX378 40563040 彩色 1/2.…...

网络安全威胁情报是什么,它对代工生产(OEM)意味着什么?
随着汽车数字环境的不断变化,网络安全基础设施及其面临的威胁也日趋复杂。 为了更好地识别、理解并最终预防这些风险,网络安全威胁情报(CTI)的管理应是一个综合多方面的过程。 以下是CTI对OEM的意义,以及如何利用网络…...

【基础篇】Docker 架构与组件 TWO
嗨,小伙伴们!我是小竹笋,一名热爱创作的工程师。上一篇我们聊了聊 Docker 的历史与发展、与虚拟机的对比以及它在行业中的应用。今天,让我们更进一步,深入探讨 Docker 的架构与关键组件。 欢迎订阅公众号:…...

03。正式拿捏ArkTS语言第一天
1, 打印日志命令 : console.log() 2, 三种基本数据类型: number 数字类型 (数字) string 字符串类型(例如:“我是字符串”) boolean 布尔类型 (true 或者 false) ***…...

【PyTorch][chapter 27][李宏毅深度学习][attention-3]
前言: 前面重点讲了self-attention, mulitHead self-attention. 目录: self-attention positional Encoding 语音处理例子 跟CNN区别 跟 RNN 区别 一 self-attention 回顾 优点 1 解决了长序列依赖问题 2 并行计算 缺点 1 开销变大 增加了 Q…...

java-数据结构与算法-02-数据结构-05-栈
文章目录 1. 栈1. 概述2. 链表实现3. 数组实现4. 应用 2. 习题E01. 有效的括号-Leetcode 20E02. 后缀表达式求值-Leetcode 120E03. 中缀表达式转后缀E04. 双栈模拟队列-Leetcode 232E05. 单队列模拟栈-Leetcode 225 1. 栈 1. 概述 计算机科学中,stack 是一种线性的…...
Python 管理依赖包(pip, virtualenv)
在Python编程中,管理依赖包是开发工作的重要组成部分。正确管理依赖包可以确保代码在不同环境中的一致性和可移植性,避免版本冲突和依赖地狱等问题。Python中常用的依赖包管理工具包括pip和virtualenv。 一、pip pip是Python官方推荐的包管理工具&…...
Bigdecimal 导出为excel时显示未0E-10,不是0,怎么解决
在使用 BigDecimal 导出到 Excel 时,如果遇到显示为 0E-10 而不是 0 的问题,这通常是因为 BigDecimal 对象的精度问题。0E-10 表示的是 0 乘以 10 的 -10 次方,这在数学上等同于…...

springboot项目从jdk8升级为jdk17过程记录
背景:公司有升级项目jdk的规划,计划从jdk8升级到jdk11 开始 首先配置本地的java_home 参考文档:Mac环境下切换JDK版本及不同的maven-CSDN博客 将pom.xml中jdk1.8相关的版本全部改为jdk17,主要是maven编译插件之类的,…...

list、tuple、set和dict传参机制
1、list、tuple、set和dict传参机制 # -------------list------------- def f1(my_list):print(f"②f1()my_list:{my_list} 地址是:{id(my_list)}") # ["tom","mary","hsp"] 0x1122my_list[0]"jack"print(f&quo…...

Redis快速入门基础
Redis入门 Redis是一个基于内存的 key-value 结构数据库。mysql是二维表的接口数据库 优点: 基于内存存储,读写性能高 适合存储热点数据(热点商品、资讯、新闻) 企业应用广泛 官网:https://redis.io 中文网:https://www.redis.net.cn/ Redis下载与…...
python基础介绍
这次的专题是关于python的知识点,加油! 文章目录 1 什么是计算机(1.1 哪些可以称为计算机?(以下)(1.2 计算机可以完成的工作有哪些?(1.3 一台计算机由什么构成? 2. 什么是编程(2.1 编…...

SSRF中伪协议学习
SSRF常用的伪协议 file:// 从文件系统中获取文件内容,如file:///etc/passwd dict:// 字典服务协议,访问字典资源,如 dict:///ip:6739/info: ftp:// 可用于网络端口扫描 sftp:// SSH文件传输协议或安全文件传输协议 ldap://轻量级目录访问协议 tftp:// 简单文件传输协议 gopher…...

Java | Leetcode Java题解之第284题窥视迭代器
题目: 题解: class PeekingIterator<E> implements Iterator<E> {private Iterator<E> iterator;private E nextElement;public PeekingIterator(Iterator<E> iterator) {this.iterator iterator;nextElement iterator.next(…...
哈尔滨等保定级的常见问题
一、哈尔滨等保测评定级标准理解问题 哈尔滨等保测评如何确定信息系统的安全保护等级? 信息系统的安全保护等级应根据其在国家安全、经济建设、社会生活中的重要程度,以及一旦遭到破坏后对国家安全、社会秩序、公共利益以及公民、法人和其他组织的合法权…...
day52 ResNet18 CBAM
在深度学习的旅程中,我们不断探索如何提升模型的性能。今天,我将分享我在 ResNet18 模型中插入 CBAM(Convolutional Block Attention Module)模块,并采用分阶段微调策略的实践过程。通过这个过程,我不仅提升…...

DAY 47
三、通道注意力 3.1 通道注意力的定义 # 新增:通道注意力模块(SE模块) class ChannelAttention(nn.Module):"""通道注意力模块(Squeeze-and-Excitation)"""def __init__(self, in_channels, reduction_rat…...

MODBUS TCP转CANopen 技术赋能高效协同作业
在现代工业自动化领域,MODBUS TCP和CANopen两种通讯协议因其稳定性和高效性被广泛应用于各种设备和系统中。而随着科技的不断进步,这两种通讯协议也正在被逐步融合,形成了一种新型的通讯方式——开疆智能MODBUS TCP转CANopen网关KJ-TCPC-CANP…...

[10-3]软件I2C读写MPU6050 江协科技学习笔记(16个知识点)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16...
【android bluetooth 框架分析 04】【bt-framework 层详解 1】【BluetoothProperties介绍】
1. BluetoothProperties介绍 libsysprop/srcs/android/sysprop/BluetoothProperties.sysprop BluetoothProperties.sysprop 是 Android AOSP 中的一种 系统属性定义文件(System Property Definition File),用于声明和管理 Bluetooth 模块相…...
GitHub 趋势日报 (2025年06月08日)
📊 由 TrendForge 系统生成 | 🌐 https://trendforge.devlive.org/ 🌐 本日报中的项目描述已自动翻译为中文 📈 今日获星趋势图 今日获星趋势图 884 cognee 566 dify 414 HumanSystemOptimization 414 omni-tools 321 note-gen …...

智能仓储的未来:自动化、AI与数据分析如何重塑物流中心
当仓库学会“思考”,物流的终极形态正在诞生 想象这样的场景: 凌晨3点,某物流中心灯火通明却空无一人。AGV机器人集群根据实时订单动态规划路径;AI视觉系统在0.1秒内扫描包裹信息;数字孪生平台正模拟次日峰值流量压力…...

OPenCV CUDA模块图像处理-----对图像执行 均值漂移滤波(Mean Shift Filtering)函数meanShiftFiltering()
操作系统:ubuntu22.04 OpenCV版本:OpenCV4.9 IDE:Visual Studio Code 编程语言:C11 算法描述 在 GPU 上对图像执行 均值漂移滤波(Mean Shift Filtering),用于图像分割或平滑处理。 该函数将输入图像中的…...

dify打造数据可视化图表
一、概述 在日常工作和学习中,我们经常需要和数据打交道。无论是分析报告、项目展示,还是简单的数据洞察,一个清晰直观的图表,往往能胜过千言万语。 一款能让数据可视化变得超级简单的 MCP Server,由蚂蚁集团 AntV 团队…...

听写流程自动化实践,轻量级教育辅助
随着智能教育工具的发展,越来越多的传统学习方式正在被数字化、自动化所优化。听写作为语文、英语等学科中重要的基础训练形式,也迎来了更高效的解决方案。 这是一款轻量但功能强大的听写辅助工具。它是基于本地词库与可选在线语音引擎构建,…...