Spring Boot 动态数据源实操指南
在实际开发中,我们经常会遇到需要动态切换数据源的场景,比如多租户系统、读写分离、分库分表等。Spring Boot 提供了灵活的配置方式,结合 AbstractRoutingDataSource
可以轻松实现动态数据源切换。本文将带你一步步实现 Spring Boot 动态数据源的配置与使用。
一、动态数据源的原理
Spring Boot 的动态数据源核心原理是通过 AbstractRoutingDataSource
实现数据源的路由。AbstractRoutingDataSource
是一个抽象类,它允许我们根据当前的上下文(如线程局部变量)动态选择目标数据源。
核心流程:
- 定义多个数据源(如主库、从库)。
- 继承
AbstractRoutingDataSource
,实现determineCurrentLookupKey()
方法,返回当前线程需要使用的数据源标识。 - 通过 AOP 或手动切换的方式,动态设置数据源标识。
二、实现步骤
1. 创建 Spring Boot 项目
使用 Spring Initializr 创建一个 Spring Boot 项目,添加以下依赖:
- Spring Web
- Spring Data JPA
- MySQL Driver
- HikariCP(连接池)
<dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-jpa</artifactId></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId></dependency><dependency><groupId>com.zaxxer</groupId><artifactId>HikariCP</artifactId></dependency>
</dependencies>
2. 配置多数据源
在 application.yml
中配置多个数据源,例如主库和从库:
spring:datasource:master:jdbc-url: jdbc:mysql://localhost:3306/master_dbusername: rootpassword: rootdriver-class-name: com.mysql.cj.jdbc.Driverslave:jdbc-url: jdbc:mysql://localhost:3306/slave_dbusername: rootpassword: rootdriver-class-name: com.mysql.cj.jdbc.Driver
3. 创建数据源配置类
通过 Java 配置类加载多个数据源。
@Configuration
public class DataSourceConfig {@Bean(name = "masterDataSource")@ConfigurationProperties(prefix = "spring.datasource.master")public DataSource masterDataSource() {return DataSourceBuilder.create().build();}@Bean(name = "slaveDataSource")@ConfigurationProperties(prefix = "spring.datasource.slave")public DataSource slaveDataSource() {return DataSourceBuilder.create().build();}
}
4. 实现动态数据源路由
创建 DynamicDataSource
类继承 AbstractRoutingDataSource
,并实现 determineCurrentLookupKey()
方法。
public class DynamicDataSource extends AbstractRoutingDataSource {@Overrideprotected Object determineCurrentLookupKey() {return DataSourceContextHolder.getDataSourceKey();}
}
5. 创建数据源上下文管理类
使用 ThreadLocal
保存当前线程的数据源标识。
public class DataSourceContextHolder {private static final ThreadLocal<String> contextHolder = new ThreadLocal<>();public static void setDataSourceKey(String key) {contextHolder.set(key);}public static String getDataSourceKey() {return contextHolder.get();}public static void clearDataSourceKey() {contextHolder.remove();}
}
6. 配置动态数据源
将多个数据源注入到 DynamicDataSource
中。
@Configuration
public class DynamicDataSourceConfig {@Beanpublic DataSource dynamicDataSource(@Qualifier("masterDataSource") DataSource masterDataSource,@Qualifier("slaveDataSource") DataSource slaveDataSource) {Map<Object, Object> targetDataSources = new HashMap<>();targetDataSources.put("master", masterDataSource);targetDataSources.put("slave", slaveDataSource);DynamicDataSource dynamicDataSource = new DynamicDataSource();dynamicDataSource.setDefaultTargetDataSource(masterDataSource); // 默认数据源dynamicDataSource.setTargetDataSources(targetDataSources);return dynamicDataSource;}
}
7. 配置事务管理器
由于动态数据源的切换会影响事务管理,需要配置一个支持动态数据源的事务管理器。
@Bean
public PlatformTransactionManager transactionManager(DataSource dynamicDataSource) {return new DataSourceTransactionManager(dynamicDataSource);
}
8. 使用 AOP 动态切换数据源
通过 AOP 在方法执行前切换数据源。
@Aspect
@Component
public class DataSourceAspect {@Before("@annotation(com.example.demo.annotation.Master)")public void setMasterDataSource() {DataSourceContextHolder.setDataSourceKey("master");}@Before("@annotation(com.example.demo.annotation.Slave)")public void setSlaveDataSource() {DataSourceContextHolder.setDataSourceKey("slave");}@After("@annotation(com.example.demo.annotation.Master) || @annotation(com.example.demo.annotation.Slave)")public void clearDataSource() {DataSourceContextHolder.clearDataSourceKey();}
}
9. 定义注解
为了方便切换数据源,定义两个注解:@Master
和 @Slave
。
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface Master {
}@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface Slave {
}
10. 测试动态数据源
在 Service 层使用注解切换数据源。
@Service
public class UserService {@Autowiredprivate UserRepository userRepository;@Masterpublic void addUser(User user) {userRepository.save(user);}@Slavepublic List<User> getUsers() {return userRepository.findAll();}
}
三、总结
通过以上步骤,我们实现了一个简单的 Spring Boot 动态数据源切换功能。核心点包括:
- 使用
AbstractRoutingDataSource
实现数据源路由。 - 通过
ThreadLocal
管理当前线程的数据源标识。 - 使用 AOP 和注解简化数据源切换。
动态数据源切换是一个非常实用的功能,适用于多租户、读写分离等场景。希望本文能帮助你更好地理解和应用 Spring Boot 动态数据源技术!
相关文章:
Spring Boot 动态数据源实操指南
在实际开发中,我们经常会遇到需要动态切换数据源的场景,比如多租户系统、读写分离、分库分表等。Spring Boot 提供了灵活的配置方式,结合 AbstractRoutingDataSource 可以轻松实现动态数据源切换。本文将带你一步步实现 Spring Boot 动态数据…...
HBase高级技巧:解锁更强大的数据处理能力
HBase高级技巧:解锁更强大的数据处理能力 嘿,小伙伴们!在掌握了HBase的基本操作之后,今天我们将深入探讨一些HBase的高级技巧。这些技巧将帮助你在面对复杂的数据处理需求时更加得心应手,进一步提升系统的性能和可靠性…...

【进阶】JVM篇
为什么学习jvm 1、面试的需要 学过java的程序员对jvm应该不陌生,程序员为什么要学习jvm呢?其实不懂jvm也可以照样写出优质的代码,但是不懂jvm会被大厂的面试官虐的体无完肤。 2、高级程序员需要了解 jvm作用 jvm负责把编译后的字节码转换…...

DeepSeek官方推荐的AI集成系统
DeepSeek模型虽然强大先进,但是模型相当于大脑,再聪明的大脑如果没有输入输出以及执行工具也白搭,所以需要有配套工具才能让模型发挥最大的作用。下面是一个典型AI Agent架构图,包含核心组件与数据流转关系: #mermaid-…...

【动态规划篇】:当回文串遇上动态规划--如何用二维DP“折叠”字符串?
✨感谢您阅读本篇文章,文章内容是个人学习笔记的整理,如果哪里有误的话还请您指正噢✨ ✨ 个人主页:余辉zmh–CSDN博客 ✨ 文章所属专栏:动态规划篇–CSDN博客 文章目录 一.回文串类DP核心思想(判断所有子串是否是回文…...

JENKINS(全面)
一.linux系统中JENKINS的安装 注意:安装jenkins需要安装jdk,而且具体版本的jenkins有相对应的jdk版本。可参考以下链接。 Redhat Jenkins 软件包https://pkg.jenkins.io/redhat-stable/https://pkg.jenkins.io/redhat-stable/https://pkg.jenkins.io/r…...
Promise详解大全:介绍、九个方法使用和区别、返回值详解
Promise的介绍 Promise是异步编程的一种解决方案,它的构造函数是同步执行的,then 方法是异步执行的,所以Promise创建后里面的函数会立即执行,构造函数中的resolve和reject只有第一次执行有效,,也就是说Pro…...

尚硅谷爬虫note004
一、urllib库 1. python自带,无需安装 # _*_ coding : utf-8 _*_ # Time : 2025/2/11 09:39 # Author : 20250206-里奥 # File : demo14_urllib # Project : PythonProject10-14#导入urllib.request import urllib.request#使用urllib获取百度首页源码 #1.定义一…...
Debezium系列之:时区转换器,时间戳字段转换到指定时区
Debezium系列之:时区转换器,时间戳字段转换到指定时区 示例:基本配置应用TimezoneConverter SMT的效果示例:高级配置配置选项当Debezium发出事件记录时,记录中的时间戳字段的时区值可能会有所不同,这取决于数据源的类型和配置。为了在数据处理管道和应用程序中保持数据一…...

ubuntu20.04声音设置
step1:打开pavucontrol,设置Configuration和Output Devices, 注意需要有HDMI / DisplayPort (plugged in)这个图标。如果没有,就先选择Configuration -> Digital Stereo (HDMI 7) Output (unplugged) (unvailable),…...
如何设置Python爬虫的User-Agent?
在Python爬虫中设置User-Agent是模拟浏览器行为、避免被目标网站识别为爬虫的重要手段。User-Agent是一个HTTP请求头,用于标识客户端软件(通常是浏览器)的类型和版本信息。通过设置合适的User-Agent,可以提高爬虫的稳定性和成功率…...

深度学习框架探秘|TensorFlow:AI 世界的万能钥匙
在人工智能(AI)蓬勃发展的时代,各种强大的工具和框架如雨后春笋般涌现,而 TensorFlow 无疑是其中最耀眼的明星之一。它不仅被广泛应用于学术界的前沿研究,更是工业界实现 AI 落地的关键技术。今天,就让我们…...

C++:高度平衡二叉搜索树(AVLTree) [数据结构]
目录 一、AVL树 二、AVL树的理解 1.AVL树节点的定义 2.AVL树的插入 2.1更新平衡因子 3.AVL树的旋转 三、AVL的检查 四、完整代码实现 一、AVL树 AVL树是什么?我们对 map / multimap / set / multiset 进行了简单的介绍,可以发现,这几…...

建筑兔零基础自学python记录18|实战人脸识别项目——视频检测07
本次要学视频检测,我们先回顾一下图片的人脸检测建筑兔零基础自学python记录16|实战人脸识别项目——人脸检测05-CSDN博客 我们先把上文中代码复制出来,保留红框的部分。 然后我们来看一下源代码: import cv2 as cvdef face_detect_demo(…...

【MySQL数据库】Ubuntu下的mysql
目录 1,安装mysql数据库 2,mysql默认安装路径 3,my.cnf配置文件? 4,mysql运用的相关指令及说明 5,数据库、表的备份和恢复 mysql是一套给我们提供数据存取的,更加有利于管理数据的服务的网络程序。下…...

[MySQL#1] database概述 常见的操作指令 MySQL架构 存储引擎
#1024程序员节|征文# 目录 一. 数据库概念 0.连接服务器 1. 什么是数据库 口语中的数据库 为什么数据不直接以文件形式存储,而需要使用数据库呢? 总结 二. ??基础操作 三. 主流数据库 四. 基础知识 服务器,数据库&…...

1.从零开始学会Vue--{{基础指令}}
全新专栏带你快速掌握Vue2Vue3 1.插值表达式{{}} 插值表达式是一种Vue的模板语法 我们可以用插值表达式渲染出Vue提供的数据 1.作用:利用表达式进行插值,渲染到页面中 表达式:是可以被求值的代码,JS引擎会将其计算出一个结果 …...

VS2022中.Net Api + Vue 从创建到发布到IIS
VS2022中.Net Api Vue 从创建到发布到IIS 前言一、先决条件二、创建项目三、运行项目四、增加API五、发布到IIS六、设置Vue的发布 前言 最近从VS2019 升级到了VS2022,终于可以使用官方的.Net Vue 组合了,但是使用过程中还是有很多问题,这里记录一下. 一、先决条件 Visual …...

RFID技术在制造环节的应用与价值
在现代制造业中,信息化和智能化已经成为企业提升竞争力的重要手段。RFID技术因其非接触式、远距离和高效识别的特点,广泛应用于生产的多个环节。本文将详细解读生产过程中RFID的关键应用场景,并结合实际案例,展示其为制造业带来的…...

(前端基础)HTML(一)
前提 W3C:World Wide Web Consortium(万维网联盟) Web技术领域最权威和具有影响力的国际中立性技术标准机构 其中标准包括:机构化标准语言(HTML、XML) 表现标准语言(CSS) 行为标准…...

idea大量爆红问题解决
问题描述 在学习和工作中,idea是程序员不可缺少的一个工具,但是突然在有些时候就会出现大量爆红的问题,发现无法跳转,无论是关机重启或者是替换root都无法解决 就是如上所展示的问题,但是程序依然可以启动。 问题解决…...

深入剖析AI大模型:大模型时代的 Prompt 工程全解析
今天聊的内容,我认为是AI开发里面非常重要的内容。它在AI开发里无处不在,当你对 AI 助手说 "用李白的风格写一首关于人工智能的诗",或者让翻译模型 "将这段合同翻译成商务日语" 时,输入的这句话就是 Prompt。…...

【力扣数据库知识手册笔记】索引
索引 索引的优缺点 优点1. 通过创建唯一性索引,可以保证数据库表中每一行数据的唯一性。2. 可以加快数据的检索速度(创建索引的主要原因)。3. 可以加速表和表之间的连接,实现数据的参考完整性。4. 可以在查询过程中,…...

什么是库存周转?如何用进销存系统提高库存周转率?
你可能听说过这样一句话: “利润不是赚出来的,是管出来的。” 尤其是在制造业、批发零售、电商这类“货堆成山”的行业,很多企业看着销售不错,账上却没钱、利润也不见了,一翻库存才发现: 一堆卖不动的旧货…...
ffmpeg(四):滤镜命令
FFmpeg 的滤镜命令是用于音视频处理中的强大工具,可以完成剪裁、缩放、加水印、调色、合成、旋转、模糊、叠加字幕等复杂的操作。其核心语法格式一般如下: ffmpeg -i input.mp4 -vf "滤镜参数" output.mp4或者带音频滤镜: ffmpeg…...
第25节 Node.js 断言测试
Node.js的assert模块主要用于编写程序的单元测试时使用,通过断言可以提早发现和排查出错误。 稳定性: 5 - 锁定 这个模块可用于应用的单元测试,通过 require(assert) 可以使用这个模块。 assert.fail(actual, expected, message, operator) 使用参数…...
镜像里切换为普通用户
如果你登录远程虚拟机默认就是 root 用户,但你不希望用 root 权限运行 ns-3(这是对的,ns3 工具会拒绝 root),你可以按以下方法创建一个 非 root 用户账号 并切换到它运行 ns-3。 一次性解决方案:创建非 roo…...

12.找到字符串中所有字母异位词
🧠 题目解析 题目描述: 给定两个字符串 s 和 p,找出 s 中所有 p 的字母异位词的起始索引。 返回的答案以数组形式表示。 字母异位词定义: 若两个字符串包含的字符种类和出现次数完全相同,顺序无所谓,则互为…...
Swagger和OpenApi的前世今生
Swagger与OpenAPI的关系演进是API标准化进程中的重要篇章,二者共同塑造了现代RESTful API的开发范式。 本期就扒一扒其技术演进的关键节点与核心逻辑: 🔄 一、起源与初创期:Swagger的诞生(2010-2014) 核心…...

在 Spring Boot 中使用 JSP
jsp? 好多年没用了。重新整一下 还费了点时间,记录一下。 项目结构: pom: <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://ww…...