【mybatis-plus】多数据源切换[dynamic-datasource] 手动切换数据源

Springboot+mybatis-plus+dynamic-datasource+Druid 手动切换数据源

文章目录

  • Springboot+mybatis-plus+dynamic-datasource+Druid 手动切换数据源
  • 0.前言
  • 1. 多数据源核心类浅析
    • 1. 1. DynamicDataSourceContextHolder切换数据源核心类
    • 1.2. DynamicRoutingDataSource
  • 2.基于核心类的理解我们实现自定义的数据源切换方案
    • 2.1. 在过滤器[filter]里切换
      • 从Header 中获取数据库标识
    • 2.2. 拦截器里切换数据源
      • DataSourceInterceptor的拦截器
    • 2.2. 方法内部硬编码切换
  • 3. 参考资料

0.前言

苞米豆团队 dynamic-datasource 支持多种数据源切换方案,核心都是基于DynamicDataSourceContextHolder。本文我们利用filter和拦截器,以及方法中硬编码 这三种方式动态手动切换数据源。
在这里插入图片描述

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

1. 多数据源核心类浅析

在写切换方法之前,我们先来了解一下dynamic-datasource 的两个核心类。

1. 1. DynamicDataSourceContextHolder切换数据源核心类

DynamicDataSourceContextHolder 用于动态切换数据源的上下文工具类。在使用多数据源的情况下,它可以帮助在运行时选择要使用的数据源。

  1. 存储当前线程的数据源标识:DynamicDataSourceContextHolder使用线程本地变量(ThreadLocal)来存储当前线程所使用的数据源标识。这允许在同一应用程序中的不同线程使用不同的数据源。
 ThreadLocal<Deque<String>> LOOKUP_KEY_HOLDER = new NamedThreadLocal<Deque<String>>("dynamic-datasource") 
  1. 通过调用DynamicDataSourceContextHolder.setDataSourceKey(String dataSourceKey)方法,可以将当前线程的数据源标识设置为指定的值。数据源标识通常是一个字符串,用于识别要使用的具体数据源。

  2. 通过调用DynamicDataSourceContextHolder.getDataSourceKey()方法,可以获取当前线程正在使用的数据源标识。这对于在代码中动态选择数据源非常有用。

  3. 在使用完特定数据源后,通过调用DynamicDataSourceContextHolder.clearDataSourceKey()方法,可以清除当前线程的数据源标识。这将避免数据源标识被错误地保留在其他线程中。
    在这里插入图片描述

1.2. DynamicRoutingDataSource

基于Spring 的JDBC 提供的AbstractDataSource类来创建自定义的数据源实现.
·DynamicRoutingDataSource·通过扩展AbstractRoutingDataSource,可以自定义路由规则。您可以实现determineCurrentLookupKey()方法,根据特定的规则选择要使用的数据源标识(如数据库名称、租户ID等)。根据路由规则,每个数据访问操作将使用相应的数据源。DynamicRoutingDataSource可根据运行时的条件或业务需求动态切换数据源。通过更新或改变路由规则,您可以实现动态切换数据源,以适应不同的场景或需求。例如,根据请求的租户ID选择不同的数据库,或者根据时间段选择不同的读写数据源。我们打开源码可以看到此处已经包含了所有数据库。
在这里插入图片描述

2.基于核心类的理解我们实现自定义的数据源切换方案

2.1. 在过滤器[filter]里切换

在使用 dynamic-datasource 库时,您可以通过过滤器(Filter)来实现在请求处理过程中切换数据源。下面是一种基本的实现方式:

  1. 创建 DynamicDataSourceFilter 在过滤器的 doFilter 方法中,获取当前请求的上下文信息,例如请求参数、请求头等。
    根据上下文信息,判断应该使用哪个数据源,然后调用 DynamicDataSourceContextHolder.push(dataSourceKey ) 方法设置数据源标识。
  @Component@WebFilter(filterName = "dsFilter", urlPatterns = {"/userInfo/*"})public class DynamicDataSourceFilter implements Filter {@Overridepublic void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {// 获取上下文信息,判断应该使用哪个数据源String dataSourceKey = determineDataSourceKey(request);// 设置数据源标识DynamicDataSourceContextHolder.push(dataSourceKey );try {// 继续处理请求chain.doFilter(request, response);} finally {// 清除数据源标识DynamicDataSourceContextHolder.poll();}}// 根据请求信息确定数据源标识private String determineDataSourceKey(ServletRequest request) {// 根据请求参数、请求头等进行逻辑判断,返回相应的数据源标识// ...}// 其他方法实现,如初始化和销毁方法// ...}

从Header 中获取数据库标识

import com.baomidou.dynamic.datasource.DynamicRoutingDataSource;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DynamicDataSourceProperties;
import com.baomidou.dynamic.datasource.toolkit.DynamicDataSourceContextHolder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;@Component
@WebFilter(filterName = "dsFilter", urlPatterns = {"/userInfo/*"})
public class DynamicDataSourceFilter implements Filter {private static final String DATA_SOURCE_HEADER = "X-Data-Source"; // 假设 Header 名称为 "X-Data-Source"@Autowiredprivate DynamicRoutingDataSource dynamicRoutingDataSource;@Overridepublic void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)throws IOException, ServletException {HttpServletRequest request = (HttpServletRequest) servletRequest;String dataSourceKey = determineDataSourceKey(request);try {// 切换数据源DynamicDataSourceContextHolder.push(dataSourceKey);filterChain.doFilter(servletRequest, servletResponse);} finally {// 恢复默认数据源DynamicDataSourceContextHolder.poll();}}private String determineDataSourceKey(HttpServletRequest request) {String dataSourceKey = request.getHeader(DATA_SOURCE_HEADER);// 根据实际需求进行数据源 key 的处理,例如校验、转换等return dataSourceKey;}
}

2.2. 拦截器里切换数据源

可以使用DynamicDataSourceContextHolder 在拦截器中使用

DataSourceInterceptor的拦截器

import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;public class DataSourceInterceptor implements HandlerInterceptor {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {String dataBaseCode = request.getHeader("dataBaseCode");DynamicDataSourceContextHolder.push(dataBaseCode);return true;}@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {DynamicDataSourceContextHolder.poll();}
}

在Spring的配置中注册这个拦截器:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;@Configuration
public class WebMvcConfig implements WebMvcConfigurer {@Autowiredprivate DataSourceInterceptor dataSourceInterceptor;@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(dataSourceInterceptor).addPathPatterns("/**");}
}

2.2. 方法内部硬编码切换

 if (dbHandelVO.getParam() == null) {return E6WrapperUtil.ok();}String dataBaseCode = dbHandelVO.getDataBaseCode();if (!StringUtils.isEmpty(dataBaseCode)) {DynamicDataSourceContextHolder.push(dataBaseCode);}try {dbHandelMapper.executeInsert(dbHandelVO.getParam());} catch (Exception e) {throw new E6Exception(e.getMessage(), e);} finally {//移除当前数据源if (!StringUtils.isEmpty(dataBaseCode)) {DynamicDataSourceContextHolder.poll();}}

3. 参考资料

  1. dynamic-datasource GitHub 仓库 ↗:dynamic-datasource 的官方 GitHub 仓库,包含源代码、文档和示例等资源。

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

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

相关文章

在windows 安装JDK17 指南

一、下载jdk 去oracle官网下载jdk压缩包&#xff0c; 下载地址&#xff1a;https://www.oracle.com/java/technologies/downloads/#java17 二、解压jdk 将下载好的jdk压缩包&#xff0c;解压到要安装jdk的路径&#xff08;不要有中文&#xff09;&#xff0c; 三、配置环…

电商平台api对接货源

如今&#xff0c;电商平台已经成为了人们购物的主要途径之一。 然而&#xff0c;对于电商平台来说&#xff0c;货源对接一直是一个比较棘手的问题。为了解决这个问题&#xff0c;越来越多的电商平台开始使用API来对接货源。 API&#xff0c;即应用程序接口&#xff0c;是一种允…

ubuntu 22.04安装cuda、cudnn、conda、pytorch

1、cuda 视频连接 https://www.bilibili.com/video/BV1bW4y197Mo/?spm_id_from333.999.0.0&vd_source3b42b36e44d271f58e90f86679d77db7cuda 11.8 https://developer.nvidia.com/cuda-toolkit-archive点击进入 https://developer.nvidia.com/cuda-11-8-0-download-arc…

【ccf-csp题解】第0次csp认证-第四题-有趣的数-题解

题目描述 思路说明 本题涉及组合数学的知识 目的是在n个空位上放置0、1、2、3&#xff0c;问符合题意的放法有多少种 首先注意到一个重要的事实&#xff1a; 只要0和1的位置已经确定&#xff0c;那么2和3的摆放就十分容易了 那么把所有情况分为n-2种&#xff1a; 第一种…

【IMX6ULL驱动开发学习】11.Linux之SPI驱动

参考&#xff1a;驱动程序开发&#xff1a;SPI设备驱动_spi驱动_邓家文007的博客-CSDN博客 目录 一、SPI驱动简介 1.1 SPI架构概述 1.2 SPI适配器&#xff08;控制器&#xff09;数据结构 1.2 SPI设备数据结构 1.3 SIP设备驱动 1.4 接口函数 二、SPI驱动模板 一、SPI驱动…

[羊城杯 2023] web

文章目录 D0nt pl4y g4m3!!! D0n’t pl4y g4m3!!! 打开题目&#xff0c;可以判断这里为php Development Server 启动的服务 查询得知&#xff0c;存在 PHP<7.4.21 Development Server源码泄露漏洞(参考文章) 抓包&#xff0c;构造payload 得到源码 class Pro{private $ex…

Kubernetes(k8s) 架构原理一文详解

目录 一、k8s 概述 1.什么是k8s&#xff1f; 2.特性 3.主要功能 三、集群架构与组件 1.Master 组件 &#xff08;1&#xff09;Kube-apiserver &#xff08;2&#xff09;Kube-controller-manager &#xff08;3&#xff09;Kube-scheduler 2.配置存储中心 3.Node 组…

Flink基础实操-计算单词出现次数

&#x1f947;&#x1f947;【大数据学习记录篇】-持续更新中~&#x1f947;&#x1f947; 个人主页&#xff1a;beixi 本文章收录于专栏&#xff08;点击传送&#xff09;&#xff1a;【大数据学习】 &#x1f493;&#x1f493;持续更新中&#xff0c;感谢各位前辈朋友们支持…

深入解析Kotlin类与对象:构造、伴生、单例全面剖析

前言 本篇文章将带您了解Kotlin编程中的重要概念&#xff1a;类及构造函数、访问修饰符、伴生对象和单例模式。就像搭积木一样&#xff0c;我们会逐步揭开这些概念的面纱&#xff0c;让您轻松理解它们的作用和用法。无论您是编程新手还是有经验的开发者&#xff0c;本文都将为…

笔记本家庭版本win11上win+r,运行cmd默认没有管理员权限,如何调整为有管理员权限的

华为matebookeGo 笔记本之前有段时间不知怎么回事&#xff0c;打开运行框&#xff0c;没有了那一行“使用管理权限创建此任务”&#xff0c;而且cmd也不再是默认的管理员下的&#xff0c;这很不方便,虽然每次winr &#xff0c;输入cmd后可以按ctrlshitenter以管理员权限运行&am…

驱动开发错误汇编

本博文将会不定期更新。以便记录我的驱动开发生涯中的一些点点滴滴的技术细节和琐事。 生成时link找不到导出函数&#xff0c;比如"LNK2019 无法解析的外部符号 _FltCreateCommunicationPort32"。出现这种情况的原因是&#xff0c;驱动的编译环境忽略了所有的默认库&…

windows的redis配置sentinel

1、先安装好redis主从&#xff0c;参考我的文章&#xff0c;链接如下 redis主从&#xff08;windows版本&#xff09;_rediswindows版本_veminhe的博客-CSDN博客 2、然后配置sentinel 参考在windows上搭建redis集群&#xff08;Redis-Sentinel&#xff09; 配置时&#xf…

mac 安装java1.8

1、下载jdk1.8 https://www.oracle.com/java/technologies/downloads/#java8-mac 2、 安装jdk1.8 一路默认&#xff0c;安装后的位置在这儿。 /Library/Java/JavaVirtualMachines/jdk-1.8.jdk 3、配置环境 打开终端&#xff0c;输入命令 sudo vim /etc/profile 添加以下配…

java八股文面试[JVM]——如何打破双亲委派模型

双亲委派模型的第一次“被破坏”是重写自定义加载器的loadClass(),jdk不推荐。一般都只是重写findClass()&#xff0c;这样可以保持双亲委派机制.而loadClass方法加载规则由自己定义&#xff0c;就可以随心所欲的加载类&#xff0c;典型的打破双亲委派模型的框架和中间件有tomc…

数学建模--一维插值法的多种插值方式的Python实现

目录 1.算法流程步骤 2.算法核心代码 3.算法效果展示 1.算法流程步骤 #算法的核心就是利用scipy中的interpolate来完成工作 #一共是5种一维插值算法形式: #插值方法&#xff1a;1.阶梯插值 2.线性插值 3.2阶样条插值 4.3阶样条插值 #"nearest"阶梯插值 #"zero&…

lv3 嵌入式开发-7 linux shell脚本编程(分支语句、循环语句)

目录 1 分支语句 2 多路分支语句 3 for的用法 4 while的用法 5 循环控制语句 6 练习 1 分支语句 语法结构: if 表达式then 命令表fi 如果表达式为真, 则执行命令表中的命令; 否则退出if语句, 即执行fi后面的语句。 if和fi是条件语句的语句括号, 必须成对使用; …

LinkedList(4):多线程LinkedList 不安全情况

多线程不安全演示&#xff0c;线程越多&#xff0c;现象越明显&#xff0c;这边只启了四个线程。 package com.example.demo;import java.util.LinkedList; import java.util.UUID;public class LInkedListThread {public static void main(String[] args) {final LinkedList&…

Notepad++下载安装

自己在 找Notepad发现网上的网址参差不齐&#xff0c;自己找到的一个不错下载链接见文末&#xff01; Notepad 是一个免费的代码编辑器&#xff0c;专为在微软 Windows 环境下使用。它是一个开源项目&#xff0c;采用 GPL 许可证&#xff0c;并使用 C 编程语言结合 Win32 API 和…

ZLMeidaKit在Windows上启动时:计算机中丢失MSVCR110.dll,以及rtmp推流后无法转换为flv视频流解决

场景 ZLMediaKit在Windows上实现Rtmp流媒体服务器以及模拟rtmp推流和http-flv拉流播放&#xff1a; ZLMediaKit在Windows上实现Rtmp流媒体服务器以及模拟rtmp推流和http-flv拉流播放_zlm流媒体服务器_霸道流氓气质的博客-CSDN博客 按照以上教程启动MediaServer.exe时提示&am…

深入浅出AXI协议(4)——猝发传输

一、前言 在之前的文章中&#xff0c;我们着重介绍了关于AXI4的握手协议它可以使得传输的双方都可以自如地控制传输的速率&#xff0c;我们主要介绍了握手协议出现的3种可能情况。然后对于AXI4交易通信的握手信号的关系做出了介绍&#xff1a;&#xff08;1&#xff09;在AXI4互…