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

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;
      }
      }

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&#xff09;、就是将多个数据源全部注入到bean中&#xff0c;根据需要实现多数据源之间的切换。 2&#xff09;、使用baomidou的DS注解。见文章DS注解实现数据源动态切换 com.baomidou dynamic-datasource-spring-boot-starter 3.5.1 ##设置默认的数据源或者数据源组,默认值…...

代码随想录训练营day14

101. 对称二叉树 给你一个二叉树的根节点 root &#xff0c; 检查它是否轴对称。 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…...

功能测试进阶自动化测试如何摸清学习方向,少走弯路呢?

目录 抛开疑问&#xff0c;只做学术探讨 小白在想什么&#xff1f; 盖楼之前先打好地基&#xff0c;首先需要学习一门语言 语言入门后&#xff0c;正式踏上开始自动化成神之路&#xff0c;入门篇Selenium 玩腻了Selenium 开始接触自动化框架unittest/testNG 不满足于单元…...

检测前端是否可以ping通后端返回的ip地址

检测前端是否可以ping通后端返回的ip地址 前端检测是否可ping通ip地址&#xff08;PC端&#xff09;前端检测是否可ping通ip地址&#xff08;uniapp小程序端&#xff09; 前端检测是否可ping通ip地址&#xff08;PC端&#xff09; // 前端检测是否可ping通ip地址 ping…...

SMART司马他法则(目标管理)

S代表具体(Specific)&#xff0c;指绩效考核要切中特定的工作指标&#xff0c;不能笼统&#xff1b; M代表可度量(Measurable)&#xff0c;指绩效指标是数量化或者行为化的&#xff0c;验证这些绩效指标的数据或者信息是可以获得的&#xff1b; 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征稿中&#xff01;信息如下&#xff0c;录满为止&#xff1a; 一、期刊概况&#xff1a; 传感器类重点SCIE 【期刊简介】IF&#xff1a;2.0-2.5&#xff0c;JCR3区&#xff0c;中科院4区&#xff1b; 【版面类型】正刊&#xff1…...

移动端开发基础总结

移动端学习总结 (适合于复习) 移动端基础 技术选型&#xff1a; 单独制作移动端页面&#xff08;主流&#xff09; 流式布局&#xff08;百分比布局&#xff09;flex弹性布局&#xff08;强烈推荐&#xff09;lessrem媒体查询布局混合布局 响应式页面兼容移动端&#xff08;…...

小X学游泳(深搜)

第一题 题目描述 小X想要学游泳。 这天&#xff0c;小X来到了游泳池&#xff0c;发现游泳池可以用N行M列的格子来表示&#xff0c;每个格子的面积都是1&#xff0c;且格子内水深相同。 由于小X刚刚入门&#xff0c;他只能在水深相同的地方游泳。为此&#xff0c;他把整个游泳池…...

分布式协议与算法——拜占庭将军问题

拜占庭将军问题 背景&#xff1a;以战国时期为背景 战国时期&#xff0c;齐、楚、燕、韩、赵、魏、秦七雄并立&#xff0c;后来秦国的势力不断强大起来&#xff0c;成了东方六国的共同威胁。于是&#xff0c;这六个国家决定联合&#xff0c;全力抗秦&#xff0c;免得被秦国各个…...

MySQL数据库管理的基本原则和技巧

MySQL数据库是一种常用的关系型数据库管理系统&#xff0c;用于存储和管理大量的数据。在进行MySQL数据库管理时&#xff0c;有一些基本原则和技巧可以帮助我们更有效地管理数据库。 数据库设计原则&#xff1a; 合理规划数据表结构&#xff1a; 根据数据之间的关系和业务需求…...

SQL-每日一题【1193. 每月交易 I】

题目 Table: Transactions 编写一个 sql 查询来查找每个月和每个国家/地区的事务数及其总金额、已批准的事务数及其总金额。 以 任意顺序 返回结果表。 查询结果格式如下所示。 示例 1: 解题思路 1.题目要求我们查找每个月和每个国家/地区的事务数及其总金额、已批准的事务数…...

探析青少年口才训练在个人发展中的重要性与影响

论文题目&#xff1a;探析青少年口才训练在个人发展中的重要性与影响 摘要&#xff1a; 本论文旨在探讨青少年口才训练对个人发展的重要性和影响。通过对相关文献的综述和实证研究的分析&#xff0c;论文将阐述口才训练对青少年自信心、表达能力和思维能力的提升&#xff0c;以…...

HTML 元素的 class 和 id 属性有何区别?

聚沙成塔每天进步一点点 ⭐ 专栏简介⭐ 唯一性⭐ 选择器权重⭐ JS操作⭐ CSS和JavaScript引用⭐ 写在最后 ⭐ 专栏简介 前端入门之旅&#xff1a;探索Web开发的奇妙世界 记得点击上方或者右侧链接订阅本专栏哦 几何带你启航前端之旅 欢迎来到前端入门之旅&#xff01;这个专栏…...

关于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技术的不断革新&#xff0c;实现各种布局的方式已经多得数不胜数了。 本篇文章总结了四十二种CSS的常见布局&#xff0c;这四十二种布局可以细分为如下几类&#xff1a; 水平居中垂直居中水平垂直居中两列布局三…...

spring AOP两种动态代理

本文开始 1.什么是动态代理&#xff1f; 动态代理&#xff1a;本来是通过直接访问目标对象的&#xff0c;但是找个代理对象替你进行访问目标对象&#xff0c;这就是动态代理过程&#xff1b; 例如&#xff1a;买饭作为目标对象&#xff0c;自己不想亲自跑腿&#xff0c;就点个…...

英语——副词

副词是指在句子中表示行为或状态特征的词,常用来修饰动词、形容词、其他副词或者句子等,表示时间、地点、方式和程度等,在句子中作状语。 第一节 副词的基本形式 一、副词的构成 1.许多副词都是由形容词变化而来。 (1)大部分副词由相应形容词直接加-ly构成。quick→q…...

Vue 本地应用 记事本 v-on v-model v-for使用

新增功能 vue当中如何生成列表结构&#xff1f;使用的指令是v-for&#xff0c;同时要有一个可以生成列表的数据&#xff0c;常用的是数组。记事本里面的内容并不复杂&#xff0c;所以这里使用字符串数组就行了。 获取用户输入的内容使用绑定v-model&#xff0c;双向数据绑定&a…...

智能质检技术的核心环节:语音识别和自然语言处理

随着呼叫中心行业的快速发展和客户服务需求的不断提高&#xff0c;越来越多的企业开始采用智能质检技术&#xff0c;以提高呼叫中心的质量和效率。而在智能质检技术中&#xff0c;语音识别和自然语言处理是其核心环节&#xff0c;对于提高质检的准确性和效率具有重要作用。 语音…...

深度学习在微纳光子学中的应用

深度学习在微纳光子学中的主要应用方向 深度学习与微纳光子学的结合主要集中在以下几个方向&#xff1a; 逆向设计 通过神经网络快速预测微纳结构的光学响应&#xff0c;替代传统耗时的数值模拟方法。例如设计超表面、光子晶体等结构。 特征提取与优化 从复杂的光学数据中自…...

用docker来安装部署freeswitch记录

今天刚才测试一个callcenter的项目&#xff0c;所以尝试安装freeswitch 1、使用轩辕镜像 - 中国开发者首选的专业 Docker 镜像加速服务平台 编辑下面/etc/docker/daemon.json文件为 {"registry-mirrors": ["https://docker.xuanyuan.me"] }同时可以进入轩…...

C++八股 —— 单例模式

文章目录 1. 基本概念2. 设计要点3. 实现方式4. 详解懒汉模式 1. 基本概念 线程安全&#xff08;Thread Safety&#xff09; 线程安全是指在多线程环境下&#xff0c;某个函数、类或代码片段能够被多个线程同时调用时&#xff0c;仍能保证数据的一致性和逻辑的正确性&#xf…...

selenium学习实战【Python爬虫】

selenium学习实战【Python爬虫】 文章目录 selenium学习实战【Python爬虫】一、声明二、学习目标三、安装依赖3.1 安装selenium库3.2 安装浏览器驱动3.2.1 查看Edge版本3.2.2 驱动安装 四、代码讲解4.1 配置浏览器4.2 加载更多4.3 寻找内容4.4 完整代码 五、报告文件爬取5.1 提…...

Java多线程实现之Thread类深度解析

Java多线程实现之Thread类深度解析 一、多线程基础概念1.1 什么是线程1.2 多线程的优势1.3 Java多线程模型 二、Thread类的基本结构与构造函数2.1 Thread类的继承关系2.2 构造函数 三、创建和启动线程3.1 继承Thread类创建线程3.2 实现Runnable接口创建线程 四、Thread类的核心…...

华硕a豆14 Air香氛版,美学与科技的馨香融合

在快节奏的现代生活中&#xff0c;我们渴望一个能激发创想、愉悦感官的工作与生活伙伴&#xff0c;它不仅是冰冷的科技工具&#xff0c;更能触动我们内心深处的细腻情感。正是在这样的期许下&#xff0c;华硕a豆14 Air香氛版翩然而至&#xff0c;它以一种前所未有的方式&#x…...

C++使用 new 来创建动态数组

问题&#xff1a; 不能使用变量定义数组大小 原因&#xff1a; 这是因为数组在内存中是连续存储的&#xff0c;编译器需要在编译阶段就确定数组的大小&#xff0c;以便正确地分配内存空间。如果允许使用变量来定义数组的大小&#xff0c;那么编译器就无法在编译时确定数组的大…...

【VLNs篇】07:NavRL—在动态环境中学习安全飞行

项目内容论文标题NavRL: 在动态环境中学习安全飞行 (NavRL: Learning Safe Flight in Dynamic Environments)核心问题解决无人机在包含静态和动态障碍物的复杂环境中进行安全、高效自主导航的挑战&#xff0c;克服传统方法和现有强化学习方法的局限性。核心算法基于近端策略优化…...

Linux 内存管理实战精讲:核心原理与面试常考点全解析

Linux 内存管理实战精讲&#xff1a;核心原理与面试常考点全解析 Linux 内核内存管理是系统设计中最复杂但也最核心的模块之一。它不仅支撑着虚拟内存机制、物理内存分配、进程隔离与资源复用&#xff0c;还直接决定系统运行的性能与稳定性。无论你是嵌入式开发者、内核调试工…...

2025年渗透测试面试题总结-腾讯[实习]科恩实验室-安全工程师(题目+回答)

安全领域各种资源&#xff0c;学习文档&#xff0c;以及工具分享、前沿信息分享、POC、EXP分享。不定期分享各种好玩的项目及好用的工具&#xff0c;欢迎关注。 目录 腾讯[实习]科恩实验室-安全工程师 一、网络与协议 1. TCP三次握手 2. SYN扫描原理 3. HTTPS证书机制 二…...