当前位置: 首页 > news >正文

AbstractRoutingDataSource,spring配置多数据源问题

AbstractRoutingDataSource,spring配置多数据源问题

首先引入pom.xml依赖

        <!--测试--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><version>2.3.12.RELEASE</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-aop</artifactId><version>2.3.12.RELEASE</version></dependency><dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>2.0.1</version></dependency><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.1.1</version></dependency><dependency><groupId>com.github.pagehelper</groupId><artifactId>pagehelper-spring-boot-starter</artifactId><version>1.2.13</version></dependency><dependency><groupId>com.alibaba</groupId><artifactId>druid-spring-boot-starter</artifactId><version>1.1.18</version></dependency><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-generator</artifactId><version>3.1.1</version></dependency>

在application.yml中添加配置

spring:application:name: tmsdatasource:type: com.alibaba.druid.pool.DruidDataSourceds1:driver-class-name: Driverurl: ${url}username: ${username}password: ${password}ds2:driver-class-name: Driverurl: ${url}username: ${username}password: ${password}

其中加了两个数据库配置

添加这两个数据库的配置, 注入到bean

package com.dualdb;import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceBuilder;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;import javax.sql.DataSource;@Configuration
public class MyBootDataSourceConfig {@Bean@ConfigurationProperties(prefix = "spring.datasource.ds1")public DataSource dataSource1() {// 通过配置地址拿到spring.datasource中的配置,创建一个DruidDataSourcereturn DruidDataSourceBuilder.create().build();}@Bean@ConfigurationProperties(prefix = "spring.datasource.ds2")public DataSource dataSource2() {// 通过配置地址拿到spring.datasource中的配置,创建一个DruidDataSourcereturn DruidDataSourceBuilder.create().build();}
}

配置这两个数据源的主从关系, 及切换标识

package com.config.dualdb;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Primary;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
import org.springframework.stereotype.Component;import javax.sql.DataSource;
import java.util.HashMap;
import java.util.Map;@Component
@Primary // 有多个datasource时,将此source设置为主要注入的bean,primary
public class DynamicDatasource extends AbstractRoutingDataSource {// 数据源标识,为了保证线程安全使用threadLocalpublic static ThreadLocal<String> threadLocal = new ThreadLocal<>();@AutowiredDataSource dataSource1;@AutowiredDataSource dataSource2;/*** 此方法作用是返回当前数据源标识** @return*/@Overrideprotected Object determineCurrentLookupKey() {return threadLocal.get();}/*** 重写父类方法之前,为父类基础属性进行赋值*/@Overridepublic void afterPropertiesSet() {// 为AbstractRoutingDataSource的主要参数进行赋值// targetDataSources初始化所有数据源Map<Object, Object> targetDataSources = new HashMap<>();targetDataSources.put("ds1", dataSource1);targetDataSources.put("ds2", dataSource2);super.setTargetDataSources(targetDataSources);// defaultTargetDataSource设置默认数据源super.setDefaultTargetDataSource(dataSource1);super.afterPropertiesSet();}// 清除threadLocal变量
}

使用aop方式自动切换数据源

package com.aop;import com.config.dualdb.DynamicDatasource;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;@Component
@Aspect
@Slf4j
public class DynamicDatasourceAspect {@Pointcut("execution(public * com.mapper.test1.*.*(..))")public void pointCut1() {}@Pointcut("execution(public * com.mapper.test2.*.*(..))")public void pointCut2() {}@Before(value = "pointCut1()")public void before1(JoinPoint jp) {String name = "解析token获取用户对应的数据源";// 通过反射拿到请求的相关信息,进行解析,获取相应的标识// 根据具体业务对应的标识设置请求哪个数据源// 优化点, 根据切点, 动态切换配置DynamicDatasource.threadLocal.set("ds1");log.info(name);}@After("pointCut1()")public void after1(JoinPoint joinPoint) {DynamicDatasource.threadLocal.remove();}@Before(value = "pointCut2()")public void before2(JoinPoint jp) {String name = "解析token获取用户对应的数据源";// 通过反射拿到请求的相关信息,进行解析,获取相应的标识// 根据具体业务对应的标识设置请求哪个数据源DynamicDatasource.threadLocal.set("ds2");log.info(name);}@After("pointCut2()")public void after2(JoinPoint joinPoint) {DynamicDatasource.threadLocal.remove();}
}

简单编写aop自动切换,通过解析当前执行包名称,自动获取数据源标识符,然后设置当前数据源,注意需要修改mapper目录下的包为对应数据源名称

import com.config.dualdb.DynamicDatasource;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;@Component
@Aspect
@Slf4j
public class DynamicDatasourceAspect {@Pointcut("execution(public * com.mapper.*.*.*(..))")public void pointCut1() {}@Before(value = "pointCut1()")public void before1(JoinPoint jp) {String name = "解析token获取用户对应的数据源";// 通过反射拿到请求的相关信息,进行解析,获取相应的标识// 根据具体业务对应的标识设置请求哪个数据源final String[] split = jp.getSignature().getDeclaringTypeName().split("\\.");String flag = split[split.length - 2];DynamicDatasource.threadLocal.set(flag);log.info(name);}@After("pointCut1()")public void after1(JoinPoint joinPoint) {DynamicDatasource.threadLocal.remove();}
}

参考:
配置参考:
【spring配置多数据源】spring连接多个数据库,同一套项目配置多个数据库
声明事务参考:
mybatis(plus)多数据源

相关文章:

AbstractRoutingDataSource,spring配置多数据源问题

AbstractRoutingDataSource&#xff0c;spring配置多数据源问题 首先引入pom.xml依赖 <!--测试--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><version>2.3.12.RE…...

日常BUG—— SpringBoot项目DEBUG模式启动慢、卡死。

&#x1f61c;作 者&#xff1a;是江迪呀✒️本文关键词&#xff1a;日常BUG、BUG、问题分析☀️每日 一言 &#xff1a;存在错误说明你在进步&#xff01; 一、问题描述 我们调试程序时&#xff0c;需要使用DEBUG模式启动SpringBoot项目&#xff0c; 有时候会发…...

Linux网络编程(TCP状态转换关系)

文章目录 前言一、TCP状态转换图二、TCP连接状态转换解析三、TCP断开状态转换解析四、为什么需要有2MLS时长总结 前言 本篇文章来讲解一下TCP的状态转换关系&#xff0c;学习这个状态转换关系对于我们深入了解网络编程是非常有必要的。 一、TCP状态转换图 二、TCP连接状态转换…...

tauri-vue:快速开发跨平台软件的架子,支持自定义头部UI拖拽移动和窗口阴影效果

Tauri Vue Typescript 一个使用 taurivuets 开发跨平台软件的模板&#xff0c;支持窗口头部自定义 UI 和拖拽和窗口阴影&#xff0c;不用再自己做适配了&#xff0c;拿来即用&#xff0c;非常 nice。而且已经封装好了 tauri 的 http 请求工具&#xff0c;省去很多弯路。开源…...

做好以下几点,可以让我们延长周末体验感,好好放松!!!

工作以后常常容易感到疲于奔命&#xff0c;让我们找到适合自己方式&#xff0c;来让我们度过一个充实放松的周末! 方向一&#xff1a;分享你周末的时间规划 我们可以把每个月当做一个周期&#xff0c;制定一个简单的计划&#xff0c;如&#xff1a;第一周&#xff0c;锻炼身体…...

Python 学习笔记——代码基础

目录 Python基础知识 变量 赋值 数据类型 print用法 print格式化输出 运算符 if-else 数据结构 元组 in运算符 列表 切片 [ : ] 追加 append() 插入 insert&#xff08;&#xff09; 删除 pop() 字典 循环 for循环 for循环应用——遍历 for循环应用——累加…...

Android Studio 无法正常导入项目

Android Studio 无法正常导入 model&#xff0c;运行按钮边出现“Add Configuration”&#xff0c;可进行以下方法处理&#xff1a; 解决办法&#xff1a; 1、点击Run三角按钮左边紧挨的下拉按钮&#xff0c;选择Edit Configuration&#xff0c;选择 Default 新建一个Android…...

Grafana+Prometheus技术文档-进阶使用-监控spring-boot项目

阿丹&#xff1a; 之前已经实现了使用Prometheus来对服务器进行了监控和仪表盘的创建&#xff0c;现在就需要对这些监控方法使用在spring-boot中去。 实现思路&#xff1a; 1、集成Actuator 2、加入Prometheus的依赖 3、配置开放端口、以及开放监控 4、配置Prometheus中的配置…...

PG常用SQL

数据库 创建数据库 PostgreSQL 创建数据库可以用以下三种方式&#xff1a; 1、使用 CREATE DATABASE SQL 语句来创建。2、使用 createdb 命令来创建。3、使用 pgAdmin 工具。 CREATE DATABASE 创建数据库 CREATE DATABASE 命令需要在 PostgreSQL 命令窗口来执行&#xff0…...

分模块开发的意义及开发步骤

&#x1f40c;个人主页&#xff1a; &#x1f40c; 叶落闲庭 &#x1f4a8;我的专栏&#xff1a;&#x1f4a8; c语言 数据结构 javaweb 石可破也&#xff0c;而不可夺坚&#xff1b;丹可磨也&#xff0c;而不可夺赤。 Maven进阶 一、分模块开发1.1分模块开发的意义1.2分模块开…...

vue-router中的一些 API

在Vue.js的vue-router中&#xff0c;一些重要api 1、RouterHistory&#xff1a;这是 vue-router 提供的路由历史记录对象。它可以跟踪当前页面的路由历史&#xff0c;并提供一些方法和属性来管理导航和历史记录。在 vue-router 中&#xff0c;有两种类型的路由历史记录对象&…...

go-zero 是如何实现令牌桶限流的?

原文链接&#xff1a; 上一篇文章介绍了 如何实现计数器限流&#xff1f;主要有两种实现方式&#xff0c;分别是固定窗口和滑动窗口&#xff0c;并且分析了 go-zero 采用固定窗口方式实现的源码。 但是采用固定窗口实现的限流器会有两个问题&#xff1a; 会出现请求量超出限…...

Oracle/PL/SQL奇技淫巧之ROWNUM伪列

ROWNUM伪列 ROWNUM是一个伪列&#xff0c;它是根据每次查询的结果动态生成的一列递增编号&#xff0c;表示 Oracle 从表中选择该行的顺序&#xff0c;选择的第一行ROWNUM为1&#xff0c;第二行ROWNUM为2&#xff0c;以此类推。 注意1&#xff1a; ROWNUM伪列是在WHERE子句之…...

“MongoDB基础知识【超详细】

"探索MongoDB的无边之境&#xff1a;沉浸式数据库之旅" 欢迎来到MongoDB的精彩世界&#xff01;在这个博客中&#xff0c;我们将带您进入一个充满创新和无限潜力的数据库领域。无论您是开发者、数据工程师还是技术爱好者&#xff0c;MongoDB都将为您带来一场令人心动…...

腾讯24届校招内推

校招开始啦&#xff5e;有兴趣的话可以扫我的码投&#xff0c;也可以分享给身边找工作的同学&#xff5e; ❤投递攻略 1️⃣腾讯校招步骤&#xff0c;先微信扫码绑定内推关系&#xff0c;后在电脑上上传更改简历和部门投递 2️⃣投递时将选择投递部门&#xff0c;投递后将在…...

星际争霸之小霸王之小蜜蜂(二)--类的使用

目录 前言 一、将设置内容写在一个类里 二、设置小蜜蜂的造型 三、设置猫蜜蜂的参数 四、绘制猫蜜蜂到窗口 总结 前言 昨天我们设置好了窗口&#xff0c;下面我们需要向窗口中添加元素了。 一、将设置内容写在一个类里 我个人理解书上的意思是要创建一个类&#xff0c;将所有需…...

AndroidStudio升级Gradle之坑

最近在做旧工程的升级&#xff0c;原来的Gradle版本是4.6的&#xff0c;需要升级到7.6&#xff0c;JDK从8升级到17&#xff0c;一路淌了很多坑&#xff0c;逐个记录下吧 1、Maven仓库需要升级到https 你会遇到这个报错 Using insecure protocols with repositories, without …...

C# int ? 关键字使用方法

使用C#的时间也不算短。 但是今天看到了一个从来没有见过的写法 Int &#xff1f;这是个什么写法&#xff0c;没见过啊&#xff0c;百度了查一下&#xff0c;也在这里记录一下。 1、int? 关键字说明 (1)、int? 表示一个int类型,且该int类型可空,如果不加?的话,那么int类…...

Redis_主从复制

8. 主从复制 8.1 简介 主从库采用读写分离的方式 读操作&#xff1a;主库、从库都可以处理写操作&#xff1a;首先写到主库执行&#xff0c;然后再将主库同步给从库。 实现读写分离&#xff0c;性能扩展 容灾快速恢复 8.2 主从复制步骤 创建一个目录 ,在root下创建一个m…...

Postman 的 Pre-request Script 使用RSA加解密

文章目录 一、概述 一、概述 Postman内置的Js不支持进行RSA加解密&#xff0c;所以需要引入forgeJS来实现。在 Pre-request Script使用以下脚本&#xff1a; // ------ 导入RSA ------ if (!pm.globals.has("forgeJS")) {pm.sendRequest("https://raw.githubu…...

C++实现分布式网络通信框架RPC(3)--rpc调用端

目录 一、前言 二、UserServiceRpc_Stub 三、 CallMethod方法的重写 头文件 实现 四、rpc调用端的调用 实现 五、 google::protobuf::RpcController *controller 头文件 实现 六、总结 一、前言 在前边的文章中&#xff0c;我们已经大致实现了rpc服务端的各项功能代…...

<6>-MySQL表的增删查改

目录 一&#xff0c;create&#xff08;创建表&#xff09; 二&#xff0c;retrieve&#xff08;查询表&#xff09; 1&#xff0c;select列 2&#xff0c;where条件 三&#xff0c;update&#xff08;更新表&#xff09; 四&#xff0c;delete&#xff08;删除表&#xf…...

AI Agent与Agentic AI:原理、应用、挑战与未来展望

文章目录 一、引言二、AI Agent与Agentic AI的兴起2.1 技术契机与生态成熟2.2 Agent的定义与特征2.3 Agent的发展历程 三、AI Agent的核心技术栈解密3.1 感知模块代码示例&#xff1a;使用Python和OpenCV进行图像识别 3.2 认知与决策模块代码示例&#xff1a;使用OpenAI GPT-3进…...

Objective-C常用命名规范总结

【OC】常用命名规范总结 文章目录 【OC】常用命名规范总结1.类名&#xff08;Class Name)2.协议名&#xff08;Protocol Name)3.方法名&#xff08;Method Name)4.属性名&#xff08;Property Name&#xff09;5.局部变量/实例变量&#xff08;Local / Instance Variables&…...

定时器任务——若依源码分析

分析util包下面的工具类schedule utils&#xff1a; ScheduleUtils 是若依中用于与 Quartz 框架交互的工具类&#xff0c;封装了定时任务的 创建、更新、暂停、删除等核心逻辑。 createScheduleJob createScheduleJob 用于将任务注册到 Quartz&#xff0c;先构建任务的 JobD…...

从零实现STL哈希容器:unordered_map/unordered_set封装详解

本篇文章是对C学习的STL哈希容器自主实现部分的学习分享 希望也能为你带来些帮助~ 那咱们废话不多说&#xff0c;直接开始吧&#xff01; 一、源码结构分析 1. SGISTL30实现剖析 // hash_set核心结构 template <class Value, class HashFcn, ...> class hash_set {ty…...

Unity | AmplifyShaderEditor插件基础(第七集:平面波动shader)

目录 一、&#x1f44b;&#x1f3fb;前言 二、&#x1f608;sinx波动的基本原理 三、&#x1f608;波动起来 1.sinx节点介绍 2.vertexPosition 3.集成Vector3 a.节点Append b.连起来 4.波动起来 a.波动的原理 b.时间节点 c.sinx的处理 四、&#x1f30a;波动优化…...

有限自动机到正规文法转换器v1.0

1 项目简介 这是一个功能强大的有限自动机&#xff08;Finite Automaton, FA&#xff09;到正规文法&#xff08;Regular Grammar&#xff09;转换器&#xff0c;它配备了一个直观且完整的图形用户界面&#xff0c;使用户能够轻松地进行操作和观察。该程序基于编译原理中的经典…...

AirSim/Cosys-AirSim 游戏开发(四)外部固定位置监控相机

这个博客介绍了如何通过 settings.json 文件添加一个无人机外的 固定位置监控相机&#xff0c;因为在使用过程中发现 Airsim 对外部监控相机的描述模糊&#xff0c;而 Cosys-Airsim 在官方文档中没有提供外部监控相机设置&#xff0c;最后在源码示例中找到了&#xff0c;所以感…...

Python Einops库:深度学习中的张量操作革命

Einops&#xff08;爱因斯坦操作库&#xff09;就像给张量操作戴上了一副"语义眼镜"——让你用人类能理解的方式告诉计算机如何操作多维数组。这个基于爱因斯坦求和约定的库&#xff0c;用类似自然语言的表达式替代了晦涩的API调用&#xff0c;彻底改变了深度学习工程…...