返回顶部
首页 > 资讯 > 后端开发 > Python >mybatis-plus@DS实现动态切换数据源原理
  • 832
分享到

mybatis-plus@DS实现动态切换数据源原理

2024-04-02 19:04:59 832人浏览 薄情痞子

Python 官方文档:入门教程 => 点击学习

摘要

1、mybatis-plus @DS实现动态切换数据源原理 首先mybatis-plus使用com.baomidou.dynamic.datasource.AbstractRouti

1、mybatis-plus @DS实现动态切换数据源原理

首先mybatis-plus使用com.baomidou.dynamic.datasource.AbstractRoutingDataSource继承 AbstractDataSource接管数据源;具体实现类为com.baomidou.dynamic.datasource.DynamicRoutingDataSource。项目初始化调用public synchronized void aDDDataSource(String ds, DataSource dataSource)加载数据源,数据源存进dataSourceMap中。
private Map<String, DataSource> dataSourceMap = new LinkedHashMap<>();

private Map<String, DynamicGroupDataSource> groupDataSources = new ConcurrentHashMap<>();

public synchronized void addDataSource(String ds, DataSource dataSource) {
    if (p6spy) {
      dataSource = new P6DataSource(dataSource);
    }
    dataSourceMap.put(ds, dataSource);
    if (ds.contains(UNDERLINE)) {
      String group = ds.split(UNDERLINE)[0];
      if (groupDataSources.containsKey(group)) {
        groupDataSources.get(group).addDatasource(dataSource);
      } else {
        try {
          DynamicGroupDataSource groupDatasource = new DynamicGroupDataSource(group,
              strategy.newInstance());
          groupDatasource.addDatasource(dataSource);
          groupDataSources.put(group, groupDatasource);
        } catch (Exception e) {
          log.error("dynamic-datasource - add the datasource named [{}] error", ds, e);
          dataSourceMap.remove(ds);
        }
      }
    }
    log.info("dynamic-datasource - load a datasource named [{}] success", ds);
  }

进行数据操作时,方法会被com.baomidou.dynamic.datasource.aop.DynamicDataSourceAnnotationInterceptor拦截,

public class DynamicDataSourceAnnotationInterceptor implements MethodInterceptor {

  
  private static final String DYNAMIC_PREFIX = "#";
  private static final DynamicDataSourceClassResolver RESOLVER = new DynamicDataSourceClassResolver();
  @Setter
  private DsProcessor dsProcessor;

  @Override
  public Object invoke(MethodInvocation invocation) throws Throwable {
    try {
      DynamicDataSourceContextHolder.push(determineDatasource(invocation));
      return invocation.proceed();
    } finally {
      DynamicDataSourceContextHolder.poll();
    }
  }

  private String determineDatasource(MethodInvocation invocation) throws Throwable {
    Method method = invocation.getMethod();
    DS ds = method.isAnnotationPresent(DS.class)
        ? method.getAnnotation(DS.class)
        : AnnotationUtils.findAnnotation(RESOLVER.targetClass(invocation), DS.class);
    String key = ds.value();
    return (!key.isEmpty() && key.startsWith(DYNAMIC_PREFIX)) ? dsProcessor
        .determineDatasource(invocation, key) : key;
  }
}

拦截器首先从被拦截的方法或者类(一般@DS注解用于Service,也可用于Mapper和Controller)上寻找@DS注解,获取到@DS注解的值后将其存入com.baomidou.dynamic.datasource.toolkit.DynamicDataSourceContextHolder;DynamicDataSourceContextHolder使用ThreadLocal存储当前线程的数据源名。

public final class DynamicDataSourceContextHolder {

  
  @SuppressWarnings("unchecked")
  private static final ThreadLocal<Deque<String>> LOOKUP_KEY_HOLDER = new ThreadLocal() {
    @Override
    protected Object initialValue() {
      return new ArrayDeque();
    }
  };

  private DynamicDataSourceContextHolder() {
  }

  
  public static String peek() {
    return LOOKUP_KEY_HOLDER.get().peek();
  }

  
  public static void push(String ds) {
    LOOKUP_KEY_HOLDER.get().push(StringUtils.isEmpty(ds) ? "" : ds);
  }

  
  public static void poll() {
    Deque<String> deque = LOOKUP_KEY_HOLDER.get();
    deque.poll();
    if (deque.isEmpty()) {
      LOOKUP_KEY_HOLDER.remove();
    }
  }

  
  public static void clear() {
    LOOKUP_KEY_HOLDER.remove();
  }
}

进行数据操作时,会调用org.springframework.jdbc.datasource.getConnection()方法;getConnection()方法最终调用了com.baomidou.dynamic.datasource.AbstractRoutingDataSource的getConnection()方法;

  @Override
  public Connection getConnection() throws sqlException {
    return determineDataSource().getConnection();
  }

determineDataSource()由子类com.baomidou.dynamic.datasource.DynamicRoutingDataSource实现,可以看到DynamicRoutingDataSource从DynamicDataSourceContextHolder获取数据源名称,这个在之前拦截器处理存进ThreadLocal中,如果有数据源名称则从dataSourceMap中获取,没有则获取默认的primary数据源。

public DataSource determineDataSource() {
    return getDataSource(DynamicDataSourceContextHolder.peek());
}

public DataSource getDataSource(String ds) {
    if (StringUtils.isEmpty(ds)) {
        return determinePrimaryDataSource();
    } else if (!groupDataSources.isEmpty() && groupDataSources.containsKey(ds)) {
        log.debug("dynamic-datasource switch to the datasource named [{}]", ds);
        return groupDataSources.get(ds).determineDataSource();
    } else if (dataSourceMap.containsKey(ds)) {
        log.debug("dynamic-datasource switch to the datasource named [{}]", ds);
        return dataSourceMap.get(ds);
    }
    if (strict) {
        throw new RuntimeException("dynamic-datasource could not find a datasource named" + ds);
    }
    return determinePrimaryDataSource();
}

private DataSource determinePrimaryDataSource() {
    log.debug("dynamic-datasource switch to the primary datasource");
    return groupDataSources.containsKey(primary) ? groupDataSources.get(primary)
        .determineDataSource() : dataSourceMap.get(primary);
}

此时的数据源已经切换成了我们需要的数据源。

数据操作完成后,方法返回第二步中的拦截器,执行DynamicDataSourceContextHolder.poll();清除掉此次的数据源,避免影响后续数据操作。

附上动态数据源相关配置

spring:
  application:
    name: 
  datasource:
    dynamic:
      primary: dataSource1
      datasource:
        dataSource1:
          type: com.alibaba.druid.pool.DruidDataSource
          driverClassName: com.microsoft.sqlserver.jdbc.SQLServerDriver
          url: jdbc:sqlserver://localhost:1433;database=dataSource1
          username: 
          passWord: 
        dataSource2:
          type: com.alibaba.druid.pool.DruidDataSource
          driverClassName: com.microsoft.sqlserver.jdbc.SQLServerDriver
          url: jdbc:sqlserver://localhost:1433;instanceName=sqlserver2017;DatabaseName=dataSource2
          username: 
          password: 

pom.xml

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

相应类

@Service
//@DS("dataSource2") 放在类上就是类下所有方法都使用这个数据源。
public class XXXServiceImpl extends BaseServiceImpl<XXXMapper, XXXBean> implements XXXService {

    @DS("dataSource1")
    public void selectDataFromSource1() {
       // do somethinng;
    }
    
    @DS("dataSource2")
    public void selectDataFromSource1() {
       // do somethinng;
    }
}

**注意:**不可在事务中切换数据库,保证事务需要方法使用同一连接,使用@DS(dataSource1)方法调用@DS(dataSource2)无法切换连接,会导致方法报错。

到此这篇关于mybatis-plus @DS实现动态切换数据源原理的文章就介绍到这了,更多相关mybatis-plus @DS动态切换数据源内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

--结束END--

本文标题: mybatis-plus@DS实现动态切换数据源原理

本文链接: https://lsjlt.com/news/153933.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • mybatis-plus@DS实现动态切换数据源原理
    1、mybatis-plus @DS实现动态切换数据源原理 首先mybatis-plus使用com.baomidou.dynamic.datasource.AbstractRouti...
    99+
    2024-04-02
  • mybatisplus @DS怎么实现动态切换数据源
    今天小编给大家分享一下mybatisplus @DS怎么实现动态切换数据源的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一...
    99+
    2023-07-02
  • 详解SpringBoot+Mybatis实现动态数据源切换
    业务背景 电商订单项目分正向和逆向两个部分:其中正向数据库记录了订单的基本信息,包括订单基本信息、订单商品信息、优惠卷信息、发票信息、账期信息、结算信息、订单备注信息、收货人信息等...
    99+
    2024-04-02
  • springboot中mybatis多数据源动态切换实现
    目录多数据源配置引入 动态数据源路由实现 动态数据源切换使用 案例源码 在开发中,动态数据源配置还是用的比较多的,比如在多数据源使用方面,又或者是在多个DB之间切换方面。这里给出一个...
    99+
    2024-04-02
  • SpringBoot+Mybatis如何实现动态数据源切换
    这篇文章主要介绍了SpringBoot+Mybatis如何实现动态数据源切换,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。springboot是什么springboot一种全...
    99+
    2023-06-14
  • MyBatis Plus动态数据源
    MyBatis Plus动态数据源 简述工程搭建1. 创建Maven工程2. 依赖导入3. 编写配置文件4. 数据源5. 选择数据源注解6. 编写AOP切面5. 编写测试类 简述 Mybatis plus动态获取数据源...
    99+
    2023-08-16
    mybatis java spring mysql
  • mybatis-plus动态数据源切换不生效的问题解决
    一、问题描述 在我们项目中,既要连接mysql,又要连接TDEngine(taos),正确配置后也无法动态切换数据源执行sql 二、环境 1.依赖 com.ta...
    99+
    2023-09-09
    mybatis mysql java
  • 解决mybatis-plus动态数据源切换不生效的问题
    目录一、问题描述二、环境1.依赖2.配置三、解决方法四、测试五、问题分析一、问题描述 在我们项目中,既要连接mysql,又要连接TDEngine(taos),正确配置后也无法动态切换...
    99+
    2023-01-11
    mybatis-plus动态数据源切换 mybatis-plus动态数据源
  • 【mybatis-plus】自定义多数据源,动态切换数据源事务失效问题
    背景 做了一个和navicat一样的工具,web版工具,然后数据库链接信息都是存在一个主数据库表的里,所以这里涉及到了动态切换数据源,以及一些事务等。今天说下多数据源切换时,事务失效。 目录  一、常见的事务失效 @Transac...
    99+
    2023-09-08
    mybatis 数据库 mysql
  • 基于mybatis plus实现数据源动态添加、删除、切换,自定义数据源的示例代码
    目录简介代码示例mavne依赖数据源增加、移除数据源切换基于AOP切换基于重写处理器自定义数据源简介 基于springboot,mybatis plus集成了一套多数据源的解决方案,...
    99+
    2024-04-02
  • Springboot动态切换数据源的具体实现与原理分析
    目录前言具体实现:原理分析:总结前言 在springboot项目中只需一句代码即可实现多个数据源之间的切换: // 切换sqlserver数据源: DataSourceConte...
    99+
    2024-04-02
  • Spring AOP实现多数据源动态切换
    目录需求背景分析及实现配置多数据源信息Spring如何获取配置好的多个数据源信息?Spring如何选择使用数据源?结语需求背景 去年底,公司项目有一个需求中有个接口需要用到平台、算法...
    99+
    2024-04-02
  • java动态数据源切换怎么实现
    在Java中实现动态数据源切换有多种方式,以下是其中一种常见的实现方法:1. 创建一个数据源容器类:创建一个类来管理多个数据源对象,...
    99+
    2023-10-09
    java
  • Springboot动态切换数据源怎么实现
    这篇文章主要介绍“Springboot动态切换数据源怎么实现”,在日常操作中,相信很多人在Springboot动态切换数据源怎么实现问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Springboot动态切换数...
    99+
    2023-06-25
  • springboot怎么集成@DS注解实现数据源切换
    这篇文章主要介绍“springboot怎么集成@DS注解实现数据源切换”,在日常操作中,相信很多人在springboot怎么集成@DS注解实现数据源切换问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”sprin...
    99+
    2023-06-29
  • MyBatis-Plus集成动态多数据源的实现示例
    这里使用的是dynamic-datasource-spring-boot-starter ,它是一个基于springboot的快速集成多数据源的启动器。 1.首先在pom文件引入dy...
    99+
    2024-04-02
  • 在Spring项目中使用 Mybatis 如何实现动态切换数据源
    这篇文章将为大家详细讲解有关在Spring项目中使用 Mybatis 如何实现动态切换数据源,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。实现思路是:第一步,实现动态切换数据源:配置两个Da...
    99+
    2023-05-31
    spring mybatis 数据源
  • Springboot实现根据用户ID切换动态数据源
    首先在application.yml 文件添加一下配置  #每个库可连接最大用户数 dynamic-server: #每个服务最大建库数 database-max-num...
    99+
    2024-04-02
  • 【Java多数据源实现教程】实现动态数据源、多数据源切换方式
    前言 本文为 【Java多数据源实现教程】 相关知识,由于自己最近在做导师的项目的时候需要使用这种技术,于是自学了相关技术原理与实现,并将其整理如下,具体包含:多数据源的典型使用场景(包含业务复杂场景、读写分离场景),多数据源实现原理及实...
    99+
    2023-08-16
    java mybatis spring
  • SpringBoot基于AbstractRoutingDataSource实现多数据源动态切换
    目录一、场景二、原理三、代码示例一、场景 在生产业务中,有一些任务执行了耗时较长的查询操作,在实时性要求不高的时候,我们希望将这些查询sql分离出来,去从库查询,以减少应用对主数据库...
    99+
    2024-04-02
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作