项目应用多数据源动态切换(动态切换数据库连接)

文章目录

  • 前言
  • 准备阶段
  • 具体配置
  • 功能展示
    • 注解方式切换数据源
    • 代码方式切换数据源
      • 优化方式
  • 动态添加删除数据源
  • 事务问题
  • 参考文章

前言

最近公司的权限项目要实现多租户的功能,于是就要做数据隔离以确保每个租户的数据的安全性,但是项目中也要动态的提供能够添加租户和删除租户的功能,这就需要动态的添加数据源(数据库连接地址。。),于是就去找了找相关的资料,今天就整理总结一下如何实现这个功能。

准备阶段

项目的框架是springboot+JDBC,那么多数据源这个也有框架,使用的是dynamic-datasource这个框架,这个框架和mybatis-plus是同一家的,这里使用的是4.2.0版本,这个版本官方推荐使用的:官方地址

        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>dynamic-datasource-spring-boot-starter</artifactId>
            <version>4.2.0</version>
        </dependency>

具体配置

这里是基础的配置演示,这里配置了两个数据源,分别是master和slave1,配置文件所有以下划线 _ 分割的数据源 首部 即为组的名称,相同组名称的数据源会放在一个组下。当然如果没有这种分组的需要就不需要。同时这个 primary: master #设置默认的数据源或者数据源组,默认值即为master这个必须要设置,因为当你的一些方法或者类上没有标识使用那个数据源去执行SQL时会执行这个默认的数据源,在多说一句就是这个框架支持一主多从,多主多从这些配置,同时如果使用了分组的配置,分组中还有相应的负载均衡的策略去访问这个分组下的数据库。
在这里插入图片描述

spring:
  datasource:
    #dynamic开始多数据源配置
    dynamic:
      primary: master #设置默认的数据源或者数据源组,默认值即为master
      datasource:
        master:  # 数据源的名字:master
          username: root
          password: guyanshuang.
          driver-class-name: com.mysql.cj.jdbc.Driver
          url: jdbc:mysql:///test1
        slave1:   # 数据源的名字:slave_1
          username: root
          password: guyanshuang.
          driver-class-name: com.mysql.cj.jdbc.Driver
          url: jdbc:mysql:///test2

功能展示

注解方式切换数据源

框架提供的 @DS("数据源名称")注解可以帮助我们实现切换数据源的效果具体使用。
这是标记在方法上的,同时也可以标记到类上,那么如果方法和类都有标记注解,那么在调用标记注解的方法时,有限使用方法上注解标记的数据源。当然这种方式并不动态,因为上面说到了还要支持添加数据源的方式,那么这种方式肯定不行。
在这里插入图片描述
在这里插入图片描述

代码方式切换数据源

使用这种方式切换数据源才能算是动态的实现我上面提到的效果。
下面这两行代码就是关键,这是框架提供的方法,直接放到我们的业务代码之前即可。当然这种方式还是太繁琐了因为这两行代码的重复性太高了,作为一个程序员肯定不能做一个简单的CP工程师。

		//清除当前线程的数据源信息
		
        DynamicDataSourceContextHolder.clear();
        //切换到对应poolName(数据源名称)的数据源
        DynamicDataSourceContextHolder.push("slave_1");

同一个方法来回切换数据源也不必担心,这是线程级别的,不会相互影响
在这里插入图片描述

优化方式

既然这两行代码要在执行我们的业务代码前那么就写一个拦截器在请求进来前将这两行代码给执行了不就解决了我们重复的问题嘛。spring提供的一个拦截器HandlerInterceptor 接口

public class MyConfig implements HandlerInterceptor {
    /**
     * 请求处理程序(controller)执行之前调用。
     * @param request current HTTP request
     * @param response current HTTP response
     * @param handler chosen handler to execute, for type and/or instance evaluation
     * @return
     * @throws Exception
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        DynamicDataSourceContextHolder.clear();
        //切换到对应poolName的数据源
        DynamicDataSourceContextHolder.push("slave_1");
        return true;
    }
}

这样就做到了动态切换并且把切换的这个操作封装起来了
在这里插入图片描述

动态添加删除数据源

使用代码配置这个数据源,代码中提供的是添加的数据源操作,移除也很简单,根据数据源名称移除ds.removeDataSource(poolName);

    public void test3(){
        // 为DataSourceProperty提供相应的数据源配置信息
        DataSourceProperty dataSourceProperty=new DataSourceProperty();
        DynamicRoutingDataSource ds = (DynamicRoutingDataSource) dataSource;

        DataSource dataSource = dataSourceCreator.createDataSource(dataSourceProperty);
        // PoolName就是我们yaml配置中说的数据源名称
        ds.addDataSource("PoolName", dataSource);
    }

DataSourceProperty类就是我们在配置文件中配置的datasource相关的信息,可以看一下这个类的内部
在这里插入图片描述

在这里插入图片描述

事务问题

嵌套数据源的service中,如果操作了多个数据源,不能在最外层加上@Transaction开启事务,否则切换数据源不生效,因为这属于分布式事务了,需要用seata方案解决,如果是单个数据源(不需要切换数据源)可以用@Transaction开启事务,保证每个数据源自己的完整性。使用@Transaction注解开启的事务传播机制是required,如果需要每一个子service的事务生效就需要使用require_new,但是这又涉及到一个问题就是如果父service中的事务回滚并不会影响子service的事务回滚,所以需要使用seata。
框架也提供了一个@DSTransactional注解,只要@DSTransactional注解下任一环节发生异常,则全局多数据源事务回滚。但是@DSTransactional和@Transaction不可以混用

参考文章

入门推荐

深挖底层

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

动态修改hosts

前言 因工作需要频繁变更hosts&#xff0c; 故须自己实现一个动态管理器&#xff0c; 市面上其实已经有了类似的软件&#xff0c;比如switchhosts!但因为不好集成其他功能&#xff08;如远程连接KVM&#xff09;&#xff0c;所以还是决定自己开发一套。 原理 使用之前强烈建…

JavaScript从入门到精通系列第三十六篇:详解JavaScript中的事件监听和事件响应

文章目录 一&#xff1a;什么叫事件 1&#xff1a;概念 2&#xff1a;处理这个事件 (一)&#xff1a;鼠标单机按钮 (二)&#xff1a;鼠标双机按钮 (三)&#xff1a;鼠标移动 3&#xff1a;写法弊端 4&#xff1a;Dom Event 二&#xff1a;监听事件 1&#xff1a;元素事…

Netty实现通信框架

一、LengthFieldBasedFrameDecoder的参数解释 1、LengthFieldBasedFrameDecoder的构造方法参数 看下最多参数的构造方法 /*** Creates a new instance.** param byteOrder* the {link ByteOrder} of the length field* param maxFrameLength* the maximum len…

4面字节跳动拿到2-2Offer,入职就是30K16薪,全靠这份PDF

前言 当你开始开始去跳槽面试的时候&#xff0c;明明只是一份15K的工作&#xff0c;却问你会不会多线程&#xff0c;懂不懂高并发&#xff0c;火箭造得让你猝及不防&#xff0c;结果就是凉凉&#xff1b;现如今市场&#xff0c;多线程、高并发编程、分布式、负载均衡、集群等可…

ZYNQ实验--Petalinux--Linux C 编程入门

Linux C 编程入门 在 Windows 下我们可以使用各种各样的 IDE 进行编程&#xff0c;比如强大的 Visual Studio。Ubuntu 下也有一些可以进行编程的工具&#xff0c;但是大多都只是编辑器&#xff0c;也就是只能进行代码编辑&#xff0c;如果要编译的话就需要用到 GCC 编译器&…

【数据结构】堆(Heap):堆的实现、堆排序

目录 堆的概念及结构 ​编辑 堆的实现 实现堆的接口&#xff1a; 堆的初始化&#xff1a; 堆的打印&#xff1a; 堆的销毁&#xff1a; 获取最顶的根数据&#xff1a; 交换&#xff1a; 堆的插入&#xff1a;&#xff08;插入最后&#xff09; 向上调整&#xff1a;&#xff0…

网络和Linux网络_1(网络基础)网络概念+协议概念+网络通信原理

目录 1. 网络简介 1.1 独立模式和互联网络模式 1.2 局域网LAN和广域网WAN 2. 协议和协议分层 2.1 协议的作用 2.2 协议分层 2.3 OSI七层模型 3.2 TCP/IP四层(五层)模型 3. 网络通信原理 3.1 协议报头 3.2 局域网和解包分用 3.3 广域网和跨网络 4. 网络中的地址 4…

vscode 快速打印console.log

第一步 输入这些 {// Print Selected Variabl 为自定义快捷键中需要使用的name&#xff0c;可以自行修改"Print Selected Variable": {"body": ["\nconsole.log("," %c $CLIPBOARD: ,"," background-color: #3756d4; padding:…

二十七、W5100S/W5500+RP2040树莓派Pico<iperf 测速示例>

文章目录 1 前言2 简介2 .1 什么是网络测速技术&#xff1f;2.2 网络测速技术的优点2.3 网络测速技术数据交互原理2.4 网络测速应用场景 3 WIZnet以太网芯片4 示例概述以及使用4.1 流程图4.2 准备工作核心4.3 连接方式4.4 主要代码概述4.5 结果演示 5 注意事项6 相关链接 1 前言…

【Verilog语法】

Verilog语法 1. Verilog语法1.1 拼接运算符1.2 运算符优先级1.3 注释1.4 关键字1.5 模块结构1.6 结构语句1.7 赋值语句1.8 条件语句1.9 状态机1.10 OSI七层模型 1. Verilog语法 1.1 拼接运算符 1.2 运算符优先级 1.3 注释 1.4 关键字 1.5 模块结构 1.6 结构语句 1.7 赋值语句 …

libusb获取Windows设备实例路径DevicePath

libusb 当前版本&#xff08;1.0.26&#xff09;libusb.h 头文件提供的接口似乎没有办法获取 Windows 平台相关的设备实例路径&#xff0c;其形如&#xff1a; \\?\usb#vid_04ca&pid_7070#5&20d34a76&0&6#{a5dcbf10-6530-11d2-901f-00c04fb951ed} 只是提供了…

2023测试职业生涯必看系列:手写web自动化测试框架教程 涵盖框架源码+视频教程以及搭建流程

前言 ​ 测试行业现在70%是以手工测试为主&#xff0c;那么只有20%是自动化测试&#xff0c;剩下的10%是性能测试。 有人可能会说&#xff0c;我现在做手工&#xff0c;我为什么要学自动化呢&#xff1f;我去学性能更好性能的人更少&#xff1f; 其实&#xff0c;性能的要求比…

openssh升级9.3p2

openssh升级9.3p2 openssh-rpms目录安装编译其他机器使用 将生成的rpm包传入响应服务器 openssh-rpms目录 github上有就是总是连接不上存百度网盘了 安装编译 unzip openssh-rpms-main.zip cd openssh-rpms-main/ yum -y groupinstall "Development Tools" yum -…

零基础快速上手STM32开发(手把手保姆级教程)

零基础快速上手STM32开发&#xff08;手把手保姆级教程&#xff09; 1. 前言 作为一名嵌入式工程师&#xff0c;STM32 是必须要学习的一款单片机&#xff0c;同时这款单片机资料足够多&#xff0c;而且比较简单&#xff0c;非常适合初学者入门。 STM32 是一款由 STMicroelec…

数据结构 1、基本概念 动态数组实现

一、大O表示法 判断一个算法的效率 难点 二、线性表 1.定义 2.数学定义 线性表是具有相同类型的n&#xff08;n>0&#xff09;个数据元素的有限序列&#xff08;a0,a1,a2,...,an&#xff09;,ai是表项&#xff0c;n是表长度 3.性质 4.线性表的基本操作 1.创建线性表 2…

Redis集群,你真的学会了吗?

目录 1、为什么引入集群 1.1、先来了解集群是什么 1.2、哨兵模式的缺陷 引入集群解决了什么问题 1.3、使用集群&#xff0c;如何存储数据 2、三种主流的分片方式【经典面试题】 2.1、哈希求余算法 2.1.1、哈希求余算法的介绍 2.1.2、哈希求余算法如何扩容 2.2、一致性…

No193.精选前端面试题,享受每天的挑战和学习

🤍 前端开发工程师(主业)、技术博主(副业)、已过CET6 🍨 阿珊和她的猫_CSDN个人主页 🕠 牛客高级专题作者、在牛客打造高质量专栏《前端面试必备》 🍚 蓝桥云课签约作者、已在蓝桥云课上架的前后端实战课程《Vue.js 和 Egg.js 开发企业级健康管理项目》、《带你从入…

(只需三步)虚拟机上vm的ubuntu不能联上网怎么办

第一步&#xff1a;重启虚拟网络适配器 第二步&#xff1a;删掉网络适配器&#xff0c;重新添加 第三步&#xff1a;重启虚拟机网络服务器 sudo service network-manager stop sudo rm /var/lib/NetworkManager/NetworkManager.state sudo service network-manager start 再打…

eNSP-打开华为USG6000V1防火墙web管理页面方法

一、本地打开防火墙web管理页面 1.先在ensp中启动USG6000V1防火墙&#xff0c;启动后&#xff0c;需要输入原始username和password&#xff08;username&#xff1a;admin&#xff0c;password&#xff1a;Admin123&#xff09;&#xff0c;并修改原始密码后&#xff0c;才能配…

由浅入深学习统计学 -集中趋势的量度

由浅入深学习统计学 -集中趋势的量度 均值 &#xff08;通俗来说是平均数&#xff09; 计算公式 均值在对称数据中才有参考性。 异常数据会导致出现&#xff0c;向左偏移或者向右偏移 中位数 - &#xff08;也是属于平均数的一种&#xff09; 当偏移数据和异常数据使得均值产…