基于AbstractRoutingDataSource的mybatis动态多数据源切换

1.pom

mybatis-starter版本只能选2开头的版本,选3开头的就报错

<!--druid连接池-->
<dependency><groupId>com.alibaba</groupId><artifactId>druid-spring-boot-starter</artifactId><version>1.2.3</version>
</dependency><!--mybatis-->
<dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>2.3.1</version>
</dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.33</version><scope>runtime</scope>
</dependency><!--        切面依赖-->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-aop</artifactId>
</dependency>

2.yml配置

server:port: 9005servlet:context-path: /
# CREATE USER 'test1'@'localhost' IDENTIFIED BY 'test1'; 创建test1 用户#FLUSH PRIVILEGES;  刷新#grant all privileges on study.* to 'test1'@'localhost' with grant option;  把库study 授权给test1
spring:datasource:druid:master:driver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://localhost:3306/study?characterEncoding=utf-8username: test1password: test1#type: com.alibaba.druid.pool.DruidDataSourceslave:driver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://localhost:3306/studyslave?characterEncoding=utf-8username: test1password: test1#type: com.alibaba.druid.pool.DruidDataSourceinitial-size: 5 #初始化时建立物理连接的个数。初始化发生在显示调用init方法,或者第一次getConnection时max-active: 10 #最大连接池数量min-idle: 5 #最小连接池数量stat-view-servlet:enabled: true  # 是否启用StatvViewServlet(监控页面),默认是falsetype: com.alibaba.druid.pool.DruidDataSourcemybatis:mapper-locations: mapper/*Mapper.xmlconfiguration:map-underscore-to-camel-case: true # 驼峰命名log-impl: org.apache.ibatis.logging.stdout.StdOutImpltype-aliases-package: study.entity

3. 初始化dataSource

package study.config;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 org.springframework.context.annotation.Primary;import javax.sql.DataSource;
import java.util.HashMap;
import java.util.Map;/*** 项目初始化的时候将各个数据源注册到DynamicDataSource 中,其中firstDataSource作为默认数据源*/
@Configuration
public class DynamicDataSourceConfig {private static String MASTER = "master";private static String SLAVE = "slave";/*** 生成masterDataSource* @return*/@Bean@ConfigurationProperties("spring.datasource.druid.master")public DataSource masterDataSource(){return DruidDataSourceBuilder.create().build();}@Bean@ConfigurationProperties("spring.datasource.druid.slave")public DataSource slaveDataSource(){return DruidDataSourceBuilder.create().build();}/*** 在一个有多个实例的Bean中使用@Primary注解来标记主要实例* @param masterDataSource* @param slaveDataSource* @return*/@Bean@Primarypublic DynamicRoutingDataSource dynamicDataSource(DataSource masterDataSource, DataSource slaveDataSource) {Map<Object, Object> targetDataSources = new HashMap<>();targetDataSources.put(MASTER, masterDataSource);targetDataSources.put(SLAVE, slaveDataSource);return new DynamicRoutingDataSource(masterDataSource, targetDataSources);}}

4.继承AbstractRoutingDataSource

package study.config;import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;import javax.sql.DataSource;
import java.util.Map;public class DynamicRoutingDataSource extends AbstractRoutingDataSource {private static final ThreadLocal<String> DataSourceContextHolder = new ThreadLocal<>();/***** DynamicDataSourceConfig调用了这构造函数* @param defaultTargetDataSource* @param targetDataSources*/public DynamicRoutingDataSource(DataSource defaultTargetDataSource, Map<Object, Object> targetDataSources) {// 默认数据源super.setDefaultTargetDataSource(defaultTargetDataSource);// 所有的数据源super.setTargetDataSources(targetDataSources);// 初始化时,给resolvedDataSources 赋值super.afterPropertiesSet();}public static void setDataSource(String dataSource) {DataSourceContextHolder.set(dataSource);}public static String getDataSource() {return DataSourceContextHolder.get();}public static void clearDataSource() {DataSourceContextHolder.remove();}/*** 该类中还有一个determineTargetDataSource方法,* 是根据lookupkey从Map中获取对应的数据源,如果没有获取到,则使用默认的数据源* @return*/@Overrideprotected Object determineCurrentLookupKey() {return getDataSource();}
}

 

5.定义切换数据源的注解

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface DS {String value() default "";
}/**
* 定义切面,获取注解对应的dataSource
*/
package study.config.annotation;import com.alibaba.druid.util.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import study.config.DynamicRoutingDataSource;import java.lang.reflect.Method;@Aspect
@Component
public class DataSourceAspect {@Pointcut("@annotation(study.config.annotation.DS)")public void logPointCut() {}@Before("logPointCut()")public void doBefore(){System.out.println("方法执行前。");}@Around("logPointCut()")public Object around(ProceedingJoinPoint point) throws Throwable {MethodSignature signature = (MethodSignature)point.getSignature();Method method = signature.getMethod();DS ds = method.getAnnotation(DS.class);if(ds != null && !StringUtils.isEmpty(ds.value())){DynamicRoutingDataSource.setDataSource(ds.value());}try {return point.proceed();} finally {DynamicRoutingDataSource.clearDataSource();}}}

6.mapper定义

@Mapper
public interface UserMapper  {@DS("master")@Select("select id as id, user_name as userName, password as password,create_time as createTime from t_user where id = #{id}")public UserInfo selectByIdFromMaster(@Param("id") Integer id);@Select("select id as id, user_name as userName, password as password,create_time as createTime from t_user where id = #{id}")public UserInfo selectByIdDefault(@Param("id") Integer id);@DS("slave")@Select("select id as id, user_name as userName, password as password,create_time as createTime from t_user where id = #{id}")public UserInfo selectByIdFromSlave(@Param("id") Integer id);}@Data
@AllArgsConstructor
@NoArgsConstructor
public class UserInfo {private Integer id;private String userName;private String password;private Date createTime;private Date updateTime;public UserInfo(String userName, String password, Date createTime, Date updateTime) {this.userName = userName;this.password = password;this.createTime = createTime;this.updateTime = updateTime;}
}

6.service类


@Slf4j
@Service
public class UserServiceImpl {@Resourceprivate UserMapper userMapper;public List<UserInfo> selectById(int id){UserInfo userInfo1 = selectByIdDefault(2);UserInfo userInfo2 = selectByIdFromMaster(1);UserInfo userInfo3 = selectByIdFromSlave(5);log.info("userInfo1={}, userInfo2={}, userInfo3={}", userInfo1, userInfo2, userInfo3);return Arrays.asList(userInfo1, userInfo2);}/*** 从master库查询* @param id* @return*/public UserInfo selectByIdFromMaster(int id) {UserInfo userInfo = userMapper.selectByIdFromMaster(id);return userInfo;}/*** 从默认的库:master* @param id* @return*/public UserInfo selectByIdDefault(int id) {UserInfo userInfo = userMapper.selectByIdDefault(id);return userInfo;}/*** 从slave库查询* @param id* @return*/public UserInfo selectByIdFromSlave(int id) {return userMapper.selectByIdFromSlave(id);}}

7.运行结果

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/7930.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

0基础学汽车 丝滑炫酷摄影教学,手机剪映特效剪辑(66节也就是)

详情介绍 0基础学汽车丝滑炫酷摄影教学,手机剪映特效剪辑 课程内容:0基础学汽车 丝滑炫酷摄影教学,手机剪映特效剪辑(66节也就是) - 百创网-源码交易平台_网站源码_商城源码_小程序源码 01 AE课前基础知识(必看).mp4 02 怎样制作德关一样丝滑的作品第二种方法(苹果mac专…

【busybox记录】【shell指令】paste

目录 内容来源&#xff1a; 【GUN】【paste】指令介绍 【busybox】【paste】指令介绍 【linux】【paste】指令介绍 使用示例&#xff1a; 合并文件的行 - 默认输出&#xff08;默认是行合并&#xff09; 合并文件的行 - 一个文件占一行 合并文件的行 - 使用指定的间隔符…

5000A信号发生器使用方法

背景 gnss工作需要使用的5000A&#xff0c;所以做成文档&#xff0c;用于其他员工学习。 下载星历数据 https://cddis.nasa.gov/archive/gnss/data/daily/2024/brdc/ 修改daily中的年份&#xff0c;就可以获取相关截至时间的星历数据 brcd数据格式 第一行记录了卫星的PRN号&a…

yolo-world:”目标检测届大模型“

AI应用开发相关目录 本专栏包括AI应用开发相关内容分享&#xff0c;包括不限于AI算法部署实施细节、AI应用后端分析服务相关概念及开发技巧、AI应用后端应用服务相关概念及开发技巧、AI应用前端实现路径及开发技巧 适用于具备一定算法及Python使用基础的人群 AI应用开发流程概…

深度学习实战76-基于目标检测YOLOv5模型的迁移学习使用方法,YOLOv5的原理与结构

大家好,我是微学AI,今天给大家介绍一下深度学习实战76-基于目标检测YOLOv5模型的迁移学习使用方法,YOLOv5的原理与结构。YOLOv5(You Only Look Once version 5)是一种先进的目标检测算法,基于深度学习的单阶段目标检测模型。它的主要原理是通过一次前向传播就同时预测图像…

Redis是什么? 日常运维 Redis 需要注意什么 ? 怎么降低Redis 内存使用 节省内存?

你的项目或许已经使用 Redis 很长时间了&#xff0c;但在使用过程中&#xff0c;你可能还会或多或少地遇到以下问题&#xff1a; 我的 Redis 内存为什么增长这么快&#xff1f;为什么我的 Redis 操作延迟变大了&#xff1f;如何降低 Redis 故障发生的频率&#xff1f;日常运维…

大数据与会计专业主要学什么课程

大数据与会计专业是一个结合了传统会计知识与现代大数据技术的交叉学科&#xff0c;旨在培养既懂会计又熟悉大数据分析的复合型人才。该专业的学生将会学习以下主要课程内容&#xff1a; 会计基础课程&#xff1a;包括基础会计、财务会计、成本会计、管理会计等&#xff0c;这些…

有了这么多套件,为什么还需要APaaS

文/明道云创始人任向晖 在明道云的业务活动中&#xff0c;比较常见的一个问题是和套件应用的关系。一个有具体应用需求的客户为什么不从市场上购买现成的套件应用&#xff0c;而要选择APaaS来构建呢&#xff1f;反过来说似乎也成立&#xff0c;既然一个平台什么应用都能搭建&a…

使用双指针解决问题题集(二)

1. 有效三角形的个数 给定一个包含非负整数的数组 nums &#xff0c;返回其中可以组成三角形三条边的三元组个数。 示例 1: 输入: nums [2,2,3,4] 输出: 3 解释:有效的组合是: 2,3,4 (使用第一个 2) 2,3,4 (使用第二个 2) 2,2,3 示例 2: 输入: nums [4,2,3,4] 输出: 4 题解&a…

软件系统测试方案书(测试计划-Word原件)

2 引言 2.1 编写目的 2.3 测试人员 2.4 项目背景 2.5 测试目标 2.6 简写和缩略词 2.7 参考资料 2.8 测试提交文档 2.9 测试进度 3 测试环境 3.1 软硬件环境 4 测试工具 5 测试策略 5.1 测试阶段划分及内容 5.1.1 集成测试 5.1.2 系统测试 5.1.2.1 功能测试 5.…

深入解析智能指针:从实践到原理

&#x1f466;个人主页&#xff1a;晚风相伴 &#x1f440;如果觉得内容对你有所帮助的话&#xff0c;还请一键三连&#xff08;点赞、关注、收藏&#xff09;哦 如果内容有错或者不足的话&#xff0c;还望你能指出。 目录 智能指针的引入 内存泄漏 RAII 智能指针的使用及原…

STM32F10x移植FreeRTOS

一、获取FreeRTOS源码 &#xff08;1&#xff09;登录FreeRTOS官网&#xff1a;www.freertos.org&#xff0c;下载第一个压缩包 &#xff08;2&#xff09;通过GitHub网站&#xff1a;github.com/FreeRTOS/FreeRTOS下载&#xff0c;由于该网站服务器在国外&#xff0c;所以访问…

1688快速获取整店铺列表 采集接口php Python

在电子商务的浪潮中&#xff0c;1688平台作为中国领先的批发交易平台&#xff0c;为广大商家提供了一个展示和销售商品的广阔舞台&#xff1b;然而&#xff0c;要在众多店铺中脱颖而出&#xff0c;快速获取商品列表并进行有效营销是关键。 竞争对手分析 价格比较&#xff1a;…

【强训笔记】day12

NO.1 思路&#xff1a;哈希表&#xff0c;建立bool数组&#xff0c;将要删除的字符串存入哈希表&#xff0c;并标为true&#xff0c;再遍历要做处理的字符串&#xff0c;如果在哈希表中为false&#xff0c;就输出。 代码实现&#xff1a; #include <iostream> #includ…

喜报 | 擎创科技荣获NIISA联盟2023年度创新技术特等奖!

为深入实施创新驱动发展战略&#xff0c;紧紧把握全球科技革命和产业变革方向&#xff0c;密切跟踪前沿科技新趋势&#xff0c;经科技部中国民营促进会业务主管部门批准以及国家互联网数据中心产业技术创新战略联盟&#xff08;以下简称联盟&#xff09;总体工作安排&#xff0…

代码随想录算法训练营第十八天:二叉树的层序遍历(中间放假)

代码随想录算法训练营第十八天&#xff1a;二叉树的层序遍历&#xff08;中间放假&#xff09; ‍ ​​ 102.二叉树的层序遍历 力扣题目链接(opens new window) 给你一个二叉树&#xff0c;请你返回其按 层序遍历 得到的节点值。 &#xff08;即逐层地&#xff0c;从左到右…

Java 框架安全:Struts2 漏洞序列测试.

什么是 Struts2 框架 Struts 2 是一个用于创建企业级 Java 应用程序的开源框架。它是一个 MVC&#xff08;模型-视图-控制器&#xff09;框架&#xff0c;用于开发基于 Java EE&#xff08;Java Platform, Enterprise Edition&#xff09;的 Web 应用程序。Struts 2 主要解决…

【Linux】HTTPS

欢迎来到Cefler的博客&#x1f601; &#x1f54c;博客主页&#xff1a;折纸花满衣 &#x1f3e0;个人专栏&#xff1a;Linux 目录 &#x1f449;&#x1f3fb;HTTPS协议概念&#x1f449;&#x1f3fb;加密为什么要进行加密 &#x1f449;&#x1f3fb;常见的加密方式对称加密…

【MATLAB源码-第204期】基于matlab的语音降噪算法对比仿真,谱减法、维纳滤波法、自适应滤波法;参数可调。

操作环境&#xff1a; MATLAB 2022a 1、算法描述 语音降噪技术的目的是改善语音信号的质量&#xff0c;通过减少或消除背景噪声&#xff0c;使得语音更清晰&#xff0c;便于听者理解或进一步的语音处理任务&#xff0c;如语音识别和语音通讯。在许多实际应用中&#xff0c;如…

基于FPGA的DDS波形发生器VHDL代码Quartus仿真

名称&#xff1a;基于FPGA的DDS波形发生器VHDL代码Quartus仿真&#xff08;文末获取&#xff09; 软件&#xff1a;Quartus 语言&#xff1a;VHDL 代码功能&#xff1a; DDS波形发生器VHDL 1、可以输出正弦波、方波、三角波 2、可以控制输出波形的频率 DDS波形发生器原理…