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

news2024/11/20 10:42:48

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 {
      @Override
      public 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"

    @Autowired
    private DynamicRoutingDataSource dynamicRoutingDataSource;

    @Override
    public 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 {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
        String dataBaseCode = request.getHeader("dataBaseCode");
        DynamicDataSourceContextHolder.push(dataBaseCode);
        return true;
    }

    @Override
    public 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 {

    @Autowired
    private DataSourceInterceptor dataSourceInterceptor;

    @Override
    public 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.coloradmin.cn/o/971407.html

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

相关文章

楼兰图腾——树状数组

在完成了分配任务之后&#xff0c;西部 314 来到了楼兰古城的西部。 相传很久以前这片土地上(比楼兰古城还早)生活着两个部落&#xff0c;一个部落崇拜尖刀(V)&#xff0c;一个部落崇拜铁锹(∧)&#xff0c;他们分别用 V 和 ∧ 的形状来代表各自部落的图腾。 西部 314 在楼兰古…

面试中的时间管理:如何在有限时间内展示最大价值

&#x1f337;&#x1f341; 博主猫头虎&#xff08;&#x1f405;&#x1f43e;&#xff09;带您 Go to New World✨&#x1f341; &#x1f984; 博客首页——&#x1f405;&#x1f43e;猫头虎的博客&#x1f390; &#x1f433; 《面试题大全专栏》 &#x1f995; 文章图文…

基于SSM的新能源汽车在线租赁系统

末尾获取源码 开发语言&#xff1a;Java Java开发工具&#xff1a;JDK1.8 后端框架&#xff1a;SSM 前端&#xff1a;采用Vue技术开发 数据库&#xff1a;MySQL5.7和Navicat管理工具结合 服务器&#xff1a;Tomcat8.5 开发软件&#xff1a;IDEA / Eclipse 是否Maven项目&#x…

Mysql 高阶语句

高阶语句 对 MySQL 数据库的查询&#xff0c;除了基本的查询外&#xff0c;有时候需要对查询的结果集进行处理&#xff1b; 例如只取 10 条数据、对查询结果进行排序或分组等&#xff0c;来获取想要有用的数据 无非还是对于MySQL —— 增、删、改、查 的操作 升降序 SELECT…

电压互感器倍频感应耐压试验方法

试验方法 升压设备的容器应足够&#xff0c; 试验前应确认高压升压等设备功能正常&#xff1b; 按上图接好线&#xff0c; 三倍频发生器、 高压器外壳必须可靠接地。 将三倍频电源发生装置的输出线与被试电压互感器的一组二次绕组接线端连接好&#xff08;如 a-n 端&#xff0…

人体呼吸存在传感器成品,毫米波雷达探测感知技术,引领智能家居新潮流

随着科技的不断进步和人们生活质量的提高&#xff0c;智能化家居逐渐成为一种时尚和生活方式。 人体存在传感器作为智能家居中的重要组成部分&#xff0c;能够实时监测环境中人体是否存在&#xff0c;为智能家居系统提供更加精准的控制和联动。 在这个充满创新的时代&#xf…

测试靶场bWAPP安装部署

bWAPP&#xff08;Buggy Web Application&#xff09;是一个用于学习和练习网络应用安全的漏洞测试平台。它是一个开源的虚拟机或Docker映像&#xff0c;旨在为安全研究人员、开发人员和学生提供一个实践和演示各种Web应用漏洞的环境。 bWAPP包含了许多已知的Web应用程序漏洞&…

PAT 1164 Good in C 测试点3,4

个人学习记录&#xff0c;代码难免不尽人意。 When your interviewer asks you to write “Hello World” using C, can you do as the following figure shows? Input Specification: Each input file contains one test case. For each case, the first part gives the 26 …

「解析」YOLOv5 classify分类模板

学习深度学习有些时间了&#xff0c;相信很多小伙伴都已经接触 图像分类、目标检测甚至图像分割(语义分割)等算法了&#xff0c;相信大部分小伙伴都是从分类入门&#xff0c;接触各式各样的 Backbone算法开启自己的炼丹之路。 但是炼丹并非全是 Backbone&#xff0c;更多的是各…

Redis——数据结构介绍

Redis是一个key-value的数据库&#xff0c;key一般是String类型&#xff0c;不过value的类型是多样的&#xff1a; String&#xff1a;hello wordHash&#xff1a;{name:"Jack",age:21}List&#xff1a;[A -> B -> C -> D]Set&#xff1a;{A,B,C}SortedSet…

盖子的c++小课堂——第二十二讲:2维dp

前言 大家好&#xff0c;我又来更新了&#xff0c;今天终于有时间了aaaaaaaa 破500粉了&#xff0c;我太高兴了哈哈哈哈哈哈&#xff08;别看IP地址&#xff0c;我去北京旅游回来了&#xff0c;他没改回来&#xff09;&#xff0c;然后我马上就成为创作者一年了&#xff0c;希…

航空货运站AAT EDI 解决方案

Asia Airfreight Terminal (AAT)是一个航空货运站&#xff0c;总部设在香港国际机场&#xff0c;是亚洲首屈一指的运输枢纽。 AAT旨在成为世界上最好的航空货运站&#xff0c;将围绕成本竞争力和服务效率&#xff0c;客户服务&#xff0c;创新和员工承诺的业务战略来构建。 | 业…

Gradle下载安装教程

1、Gradle 入门 1.1、Gradle 简介 Gradle 是一款Google 推出的基于 JVM、通用灵活的项目构建工具&#xff0c;支持 Maven&#xff0c;JCenter 多种第三方仓库;支持传递性依赖管理、废弃了繁杂的xml 文件&#xff0c;转而使用简洁的、支持多种语言(例如&#xff1a;java、groo…

grpc + springboot + mybatis-plus 动态配置数据源

前言 这是我在这个网站整理的笔记&#xff0c;关注我&#xff0c;接下来还会持续更新。 作者&#xff1a;神的孩子都在歌唱 grpc springboot mybatis-plus 动态配置数据源 一. 源码解析1.1 项目初始化1.2 接口请求时候 二. web应用三. grpc应用程序 一. 源码解析 1.1 项目初…

Logback日志记录只在控制台输出sql,未写入日志文件【解决】

原因&#xff1a;持久层框架对于Log接口实现方式不一样&#xff0c;日记记录的位置及展示方式也也不一样 mybatis-plus:configuration:log-impl: org.apache.ibatis.logging.stdout.StdOutImpl # sql只会打印到控制台不会输出到日志文件种mybatis-plus:configuration:log-impl…

链路追踪Skywalking应用实战

目录 1 Skywalking应用2 agent下载3 agent应用3.1 应用名配置3.2 IDEA集成使用agent3.3 生产环境使用agent 4 Rocketbot4.1 Rocketbot-仪表盘4.2 Rocketbot-拓扑图4.3 追踪4.4 性能分析4.5 告警4.5.1 警告规则详解4.5.2 Webhook规则4.5.3 自定义Webhook消息接收 1 Skywalking应…

微服务·架构组件之服务注册与发现-Nacos

微服务组件架构之服务注册与发现之Nacos Nacos服务注册与发现流程 服务注册&#xff1a;Nacos 客户端会通过发送REST请求的方式向Nacos Server注册自己的服务&#xff0c;提供自身的元数据&#xff0c;比如ip地址、端口等信息。 Nacos Server接收到注册请求后&#xff0c;就会…

ChatGPT 案例实战趋势分析面积图制作

面积图使用HTML,JS,Echarts 来完成代码可以使用ChatGPT AIGC 来实现代码编写。 完整的代码复制如下: <!DOCTYPE html> <html> <head><meta charset="utf-8"><script src="https://cdn.bootcdn.net/ajax/libs/echarts/5.2.2/echa…

EasyPOI处理excel、CSV导入导出

1 简介 使用POI在导出导出excel、导出csv、word时代码有点过于繁琐&#xff0c;好消息是近两年在开发市场上流行一种简化POI开发的类库&#xff1a;easyPOI。从名称上就能发现就是为了简化开发。 能干什么&#xff1f; Excel的快速导入导出,Excel模板导出,Word模板导出,可以…

【kubernetes】Harbor部署及KubeSphere使用私有仓库Harbor

私有仓库Harbor https://goharbor.io/ 内容学习于马士兵云原生课程 Harbor部署 部署docker及docker-compose 略 获取Harbor安装文件 https://github.com/goharbor/harbor/releases/download/v2.4.1/harbor-offline-installer-v2.4.1.tgz tar -zxvf harbor-offline-installe…