springboot动态数据源切换
1)、就是将多个数据源全部注入到bean中,根据需要实现多数据源之间的切换。
2)、使用baomidou的@DS注解。见文章@DS注解实现数据源动态切换
com.baomidou
dynamic-datasource-spring-boot-starter
3.5.1
##设置默认的数据源或者数据源组,默认值即为master
spring.datasource.dynamic.primary=master
#设置严格模式,默认false不启动. 启动后在未匹配到指定数据源时候会抛出异常,不启动则使用默认数据源.
spring.datasource.dynamic.strict=false
postgresql 配置 主库的配置
spring.datasource.dynamic.datasource.master.url = jdbc:postgresql://localhost:5432/zhejiang_data_repository
spring.datasource.dynamic.datasource.master.username=root
spring.datasource.dynamic.datasource.master.password=root
spring.datasource.dynamic.datasource.master.driver-class-name=org.postgresql.Driver
#从库的配置
spring.datasource.dynamic.datasource.slave.url = jdbc:postgresql://localhost:5432/server_test_logdb
spring.datasource.dynamic.datasource.slave.username=postgres
spring.datasource.dynamic.datasource.slave.password=123456
spring.datasource.dynamic.datasource.slave.driver-class-name=org.postgresql.Driver
使用@DS(“slave”)注解在类或者方法,同时使用方式上优先类上
1.配置文件配置多个数据库连接
#主库
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.url=jdbc:postgresql://localhost:5432/sgeoc_sec_system
spring.datasource.username=postgres
spring.datasource.password=123456
spring.datasource.driver-class-name=org.postgresql.Driver
#从库
spring.slave-datasource.type=com.alibaba.druid.pool.DruidDataSource
spring.slave-datasource.url=jdbc:postgresql://localhost:5432/server_test_system
spring.slave-datasource.username=postgres
spring.slave-datasource.password=123456
spring.slave-datasource.driver-class-name=org.postgresql.Driver
2.注入数据源
将配置的数据源全部注入到bean中,可以设置默认的数据源,也可以动态设置系统使用的数据源。
import com.alibaba.druid.pool.DruidDataSource;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;
import org.springframework.context.annotation.Primary;
import javax.sql.DataSource;
import java.util.HashMap;
import java.util.Map;
/**
-
数据源注入
-
@author yjj
-
@version 1.0
-
@since 2022 -08-29 09:50:30
/
@Slf4j
@Configuration
public class DataSourceConfig {
/*- 主库数据源bean名称
/
public static final String MASTER_DATASOURCE = “masterDataSource”;
/* - 从库数据源bean名称
*/
public static final String SLAVE_DATASOURCE = “slaveDataSource”;
/**
- 主库数据源对象bean生成
- @param properties 配置项
- @return DruidDataSource
*/
@Bean(MASTER_DATASOURCE)
@ConfigurationProperties(prefix = “spring.datasource”)
public DruidDataSource masterDataSource(DataSourceProperties properties) {
DruidDataSource build = properties.initializeDataSourceBuilder().type(DruidDataSource.class).build();
log.info(“配置主数据库:{}”, build);
return build;
}
/**
- 从库数据源对象bean生成
- @param properties 配置项
- @return DruidDataSource
*/
@Bean(SLAVE_DATASOURCE)
@ConfigurationProperties(prefix = “spring.slave-datasource”)
public DruidDataSource slaveDataSource(DataSourceProperties properties) {
DruidDataSource build = properties.initializeDataSourceBuilder().type(DruidDataSource.class).build();
log.info(“配置从数据库:{}”, build);
return build;
}
/**
- 数据源配置
- @param masterDataSource 主库数据源对象
- @param slaveDataSource 从库数据源对象
- @return DataSource
- @Primary 优先使用这个DataSource对象bean
/
@Bean
@Primary
@DependsOn(value = {MASTER_DATASOURCE, SLAVE_DATASOURCE})
public DataSource routingDataSource(@Qualifier(MASTER_DATASOURCE) DruidDataSource masterDataSource,
@Qualifier(SLAVE_DATASOURCE) DruidDataSource slaveDataSource) {
if (StringUtils.isBlank(slaveDataSource.getUrl())) {
log.info(“没有配置从数据库,默认使用主数据库”);
return masterDataSource;
}
Map<Object, Object> map = new HashMap<>();
map.put(DataSourceConfig.MASTER_DATASOURCE, masterDataSource);
map.put(DataSourceConfig.SLAVE_DATASOURCE, slaveDataSource);
DynamicDataSource routing = new DynamicDataSource();
//设置动态数据源
routing.setTargetDataSources(map);
//设置默认数据源
routing.setDefaultTargetDataSource(masterDataSource);
log.info(“主从数据库配置完成”);
return routing;
}
}
或
@Configuration
public class DataSourceConfig {
/* - 数据源1配置
*/
@Bean(“ds1”)
@ConfigurationProperties(“spring.datasource.ds1”)
public DataSource ds1() {
return DataSourceBuilder.create().build();
}
/**
- 数据源2配置
*/
@Bean(“ds2”)
@ConfigurationProperties(“spring.datasource.ds2”)
public DataSource ds2() {
return DataSourceBuilder.create().build();
}
/**
- 动态数据源配置
*/
@Bean
@Primary
public DataSource dynamicDataSource(@Qualifier(“ds1”) DataSource ds1, @Qualifier(“ds2”) DataSource ds2) {
DynamicDataSource ds = new DynamicDataSource();
// 设置数据源映射关系
ds.setTargetDataSources(Map.of(
“ds1”, ds1,
“ds2”, ds2
));
// 设置默认数据源
ds.setDefaultTargetDataSource(ds1);
return ds;
}
}
- 主库数据源bean名称
3.实现数据源动态切换
import com.southsmart.sso.util.DataSourceUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
/**
- 动态数据源
- @author yjj
- @version 1.0
- @since 2022 -08-29 09:55:26
*/
@Slf4j
public class DynamicDataSource extends AbstractRoutingDataSource {
@Override
protected Object determineCurrentLookupKey() {
String db = DataSourceUtil.getDb();
log.info(“使用数据源:{}”, db);
return db;
}
}
4.切换数据源管理类
/**
-
数据源切换工具
-
@author yjj
-
@version 1.0
-
@since 2022 -08-29 09:54:05
/
public class DataSourceUtil {
/*- 数据源属于一个公共的资源
- 采用ThreadLocal可以保证在多线程情况下线程隔离
*/
private static final ThreadLocal contextHolder = new ThreadLocal<>();
/**
- 设置数据源名
- @param dbType the db type
*/
public static void setDb(String dbType) {
contextHolder.set(dbType);
}
/**
- 获取数据源名
- @return db
*/
public static String getDb() {
return (contextHolder.get());
}
/**
- 清除数据源名
*/
public static void clearDb() {
contextHolder.remove();
}
}
5.添加自定义注解Db,标注在方法上,指定方法内部执行时所使用的数据源
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Db {
String value();
}
6.现切面类DynamicDataSourceAspect,对所有标注了Db注解的方法进行增强
@Aspect
@Component
public class DynamicDataSourceAspect {
/**
* Mapper方法切面实现,对所有标注了Db注解的方法生效
*/
@Around(“@annotation(byx.test.Db)”)
public Object around(ProceedingJoinPoint jp) throws Throwable {
// 获取方法上的Db注解
MethodSignature methodSignature = (MethodSignature) jp.getSignature();
Method method = methodSignature.getMethod();
Db db = method.getAnnotation(Db.class);
try {// 方法执行前先设置当前数据源,再执行方法DataSourceHolder.setDataSource(db.value());return jp.proceed();} finally {// 方法结束后清理当前数据源DataSourceHolder.clear();}
}
}
7.使用方法
@Mapper
public interface UserMapper {
@Select(“SELECT * FROM users”)
@Db(“ds1”)
List listUsersFromDs1();
@Select("SELECT * FROM users")
@Db("ds2")
List<User> listUsersFromDs2();
}
相关文章:
springboot动态数据源切换
1)、就是将多个数据源全部注入到bean中,根据需要实现多数据源之间的切换。 2)、使用baomidou的DS注解。见文章DS注解实现数据源动态切换 com.baomidou dynamic-datasource-spring-boot-starter 3.5.1 ##设置默认的数据源或者数据源组,默认值…...
代码随想录训练营day14
101. 对称二叉树 给你一个二叉树的根节点 root , 检查它是否轴对称。 func isSymmetric(root *TreeNode) bool {if root nil{ return true}return judge(root.Left,root.Right) }func judge(lf *TreeNode , ri *TreeNode)bool{if lf nil && ri nil{ retu…...
功能测试进阶自动化测试如何摸清学习方向,少走弯路呢?
目录 抛开疑问,只做学术探讨 小白在想什么? 盖楼之前先打好地基,首先需要学习一门语言 语言入门后,正式踏上开始自动化成神之路,入门篇Selenium 玩腻了Selenium 开始接触自动化框架unittest/testNG 不满足于单元…...
检测前端是否可以ping通后端返回的ip地址
检测前端是否可以ping通后端返回的ip地址 前端检测是否可ping通ip地址(PC端)前端检测是否可ping通ip地址(uniapp小程序端) 前端检测是否可ping通ip地址(PC端) // 前端检测是否可ping通ip地址 ping…...
SMART司马他法则(目标管理)
S代表具体(Specific),指绩效考核要切中特定的工作指标,不能笼统; M代表可度量(Measurable),指绩效指标是数量化或者行为化的,验证这些绩效指标的数据或者信息是可以获得的; A代表可实现(Attainable)&…...
【LeetCode】删除并获得点数
删除并获得点数 题目描述算法分析编程代码空间优化 链接: 删除并获得点数 题目描述 算法分析 编程代码 class Solution { public:int deleteAndEarn(vector<int>& nums) {const int N 10001;int arr[N] {0};for(const auto& n : nums){arr[n]n;}vector<in…...
SciencePub学术 | 传感器类重点SCIE征稿中
SciencePub学术 刊源推荐: 传感器类重点SCIE征稿中!信息如下,录满为止: 一、期刊概况: 传感器类重点SCIE 【期刊简介】IF:2.0-2.5,JCR3区,中科院4区; 【版面类型】正刊࿱…...
移动端开发基础总结
移动端学习总结 (适合于复习) 移动端基础 技术选型: 单独制作移动端页面(主流) 流式布局(百分比布局)flex弹性布局(强烈推荐)lessrem媒体查询布局混合布局 响应式页面兼容移动端(…...
小X学游泳(深搜)
第一题 题目描述 小X想要学游泳。 这天,小X来到了游泳池,发现游泳池可以用N行M列的格子来表示,每个格子的面积都是1,且格子内水深相同。 由于小X刚刚入门,他只能在水深相同的地方游泳。为此,他把整个游泳池…...
分布式协议与算法——拜占庭将军问题
拜占庭将军问题 背景:以战国时期为背景 战国时期,齐、楚、燕、韩、赵、魏、秦七雄并立,后来秦国的势力不断强大起来,成了东方六国的共同威胁。于是,这六个国家决定联合,全力抗秦,免得被秦国各个…...
MySQL数据库管理的基本原则和技巧
MySQL数据库是一种常用的关系型数据库管理系统,用于存储和管理大量的数据。在进行MySQL数据库管理时,有一些基本原则和技巧可以帮助我们更有效地管理数据库。 数据库设计原则: 合理规划数据表结构: 根据数据之间的关系和业务需求…...
SQL-每日一题【1193. 每月交易 I】
题目 Table: Transactions 编写一个 sql 查询来查找每个月和每个国家/地区的事务数及其总金额、已批准的事务数及其总金额。 以 任意顺序 返回结果表。 查询结果格式如下所示。 示例 1: 解题思路 1.题目要求我们查找每个月和每个国家/地区的事务数及其总金额、已批准的事务数…...
探析青少年口才训练在个人发展中的重要性与影响
论文题目:探析青少年口才训练在个人发展中的重要性与影响 摘要: 本论文旨在探讨青少年口才训练对个人发展的重要性和影响。通过对相关文献的综述和实证研究的分析,论文将阐述口才训练对青少年自信心、表达能力和思维能力的提升,以…...
HTML 元素的 class 和 id 属性有何区别?
聚沙成塔每天进步一点点 ⭐ 专栏简介⭐ 唯一性⭐ 选择器权重⭐ JS操作⭐ CSS和JavaScript引用⭐ 写在最后 ⭐ 专栏简介 前端入门之旅:探索Web开发的奇妙世界 记得点击上方或者右侧链接订阅本专栏哦 几何带你启航前端之旅 欢迎来到前端入门之旅!这个专栏…...
关于GKPhoto点击放大没有图片只有缺省图
GKPhoto,点进去看看,人家可传递的不止有url,还有UiImage NSString *photo self.detailModel.teacherModel.teacher_picture; NSString *placeHoldStr "ing_morentouxiang"; NSMutableArray *photos [NSMutableArray new]; GKPhoto *phot…...
建议收藏!总结了 42 种前端常用布局方案
对 CSS 布局掌握程度决定你在Web开发中的开发页面速度。随着Web技术的不断革新,实现各种布局的方式已经多得数不胜数了。 本篇文章总结了四十二种CSS的常见布局,这四十二种布局可以细分为如下几类: 水平居中垂直居中水平垂直居中两列布局三…...
spring AOP两种动态代理
本文开始 1.什么是动态代理? 动态代理:本来是通过直接访问目标对象的,但是找个代理对象替你进行访问目标对象,这就是动态代理过程; 例如:买饭作为目标对象,自己不想亲自跑腿,就点个…...
英语——副词
副词是指在句子中表示行为或状态特征的词,常用来修饰动词、形容词、其他副词或者句子等,表示时间、地点、方式和程度等,在句子中作状语。 第一节 副词的基本形式 一、副词的构成 1.许多副词都是由形容词变化而来。 (1)大部分副词由相应形容词直接加-ly构成。quick→q…...
Vue 本地应用 记事本 v-on v-model v-for使用
新增功能 vue当中如何生成列表结构?使用的指令是v-for,同时要有一个可以生成列表的数据,常用的是数组。记事本里面的内容并不复杂,所以这里使用字符串数组就行了。 获取用户输入的内容使用绑定v-model,双向数据绑定&a…...
智能质检技术的核心环节:语音识别和自然语言处理
随着呼叫中心行业的快速发展和客户服务需求的不断提高,越来越多的企业开始采用智能质检技术,以提高呼叫中心的质量和效率。而在智能质检技术中,语音识别和自然语言处理是其核心环节,对于提高质检的准确性和效率具有重要作用。 语音…...
生成xcframework
打包 XCFramework 的方法 XCFramework 是苹果推出的一种多平台二进制分发格式,可以包含多个架构和平台的代码。打包 XCFramework 通常用于分发库或框架。 使用 Xcode 命令行工具打包 通过 xcodebuild 命令可以打包 XCFramework。确保项目已经配置好需要支持的平台…...
地震勘探——干扰波识别、井中地震时距曲线特点
目录 干扰波识别反射波地震勘探的干扰波 井中地震时距曲线特点 干扰波识别 有效波:可以用来解决所提出的地质任务的波;干扰波:所有妨碍辨认、追踪有效波的其他波。 地震勘探中,有效波和干扰波是相对的。例如,在反射波…...
大话软工笔记—需求分析概述
需求分析,就是要对需求调研收集到的资料信息逐个地进行拆分、研究,从大量的不确定“需求”中确定出哪些需求最终要转换为确定的“功能需求”。 需求分析的作用非常重要,后续设计的依据主要来自于需求分析的成果,包括: 项目的目的…...
Cesium1.95中高性能加载1500个点
一、基本方式: 图标使用.png比.svg性能要好 <template><div id"cesiumContainer"></div><div class"toolbar"><button id"resetButton">重新生成点</button><span id"countDisplay&qu…...
ESP32读取DHT11温湿度数据
芯片:ESP32 环境:Arduino 一、安装DHT11传感器库 红框的库,别安装错了 二、代码 注意,DATA口要连接在D15上 #include "DHT.h" // 包含DHT库#define DHTPIN 15 // 定义DHT11数据引脚连接到ESP32的GPIO15 #define D…...
多种风格导航菜单 HTML 实现(附源码)
下面我将为您展示 6 种不同风格的导航菜单实现,每种都包含完整 HTML、CSS 和 JavaScript 代码。 1. 简约水平导航栏 <!DOCTYPE html> <html lang"zh-CN"> <head><meta charset"UTF-8"><meta name"viewport&qu…...
OpenLayers 分屏对比(地图联动)
注:当前使用的是 ol 5.3.0 版本,天地图使用的key请到天地图官网申请,并替换为自己的key 地图分屏对比在WebGIS开发中是很常见的功能,和卷帘图层不一样的是,分屏对比是在各个地图中添加相同或者不同的图层进行对比查看。…...
听写流程自动化实践,轻量级教育辅助
随着智能教育工具的发展,越来越多的传统学习方式正在被数字化、自动化所优化。听写作为语文、英语等学科中重要的基础训练形式,也迎来了更高效的解决方案。 这是一款轻量但功能强大的听写辅助工具。它是基于本地词库与可选在线语音引擎构建,…...
Java + Spring Boot + Mybatis 实现批量插入
在 Java 中使用 Spring Boot 和 MyBatis 实现批量插入可以通过以下步骤完成。这里提供两种常用方法:使用 MyBatis 的 <foreach> 标签和批处理模式(ExecutorType.BATCH)。 方法一:使用 XML 的 <foreach> 标签ÿ…...
使用Spring AI和MCP协议构建图片搜索服务
目录 使用Spring AI和MCP协议构建图片搜索服务 引言 技术栈概览 项目架构设计 架构图 服务端开发 1. 创建Spring Boot项目 2. 实现图片搜索工具 3. 配置传输模式 Stdio模式(本地调用) SSE模式(远程调用) 4. 注册工具提…...
