【mybatis-plus进阶】多租户场景中多数据源自定义来源dynamic-datasource实现

news2025/1/23 2:15:11

Springboot+mybatis-plus+dynamic-datasource+Druid 多租户场景中多数据源自定义来源dynamic-datasource实现

文章目录

  • Springboot+mybatis-plus+dynamic-datasource+Druid 多租户场景中多数据源自定义来源dynamic-datasource实现
  • 0.前言
    • 1. 作者提供了接口
    • 2. 基于此接口的抽象类实现
    • 自定义负载均衡策略
    • 如何自定义
    • 多数据源懒启动配置
  • 3. 参考资料

0.前言

我们低代码平台是支持多租户的模式,用户在平台上配置了多数据源后,数据源会持久化到低代码的数据库中。多租户场景中多数据源自定义来源 是从数据库中通过查询数据源配置信息表,获取到数据库的链接信息和配置信息,然后利用 dynamic-datasource创建多数据源对象注入到容器里。
在这里插入图片描述

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

1. 作者提供了接口

在这里插入图片描述

2. 基于此接口的抽象类实现

 @Bean
    public DynamicDataSourceProvider jdbcDynamicDatasourceProvider(DynamicDataSourceProperties properties) {
        // 获取Primary动态数据源
        Map<String, DataSourceProperty> datasourceMap = properties.getDatasource();
        DataSourceProperty masterDsProperty = datasourceMap.get(properties.getPrimary());
        // 从项目配置文件里配置的主数据源中DB加载要多租户的数据源。我们主要用在低代码场景
        return new AbstractJdbcDataSourceProvider(masterDsProperty.getDriverClassName(),
                masterDsProperty.getUrl(), masterDsProperty.getUsername(), masterDsProperty.getPassword()) {
            @Override
            protected Map<String, DataSourceProperty> executeStmt(Statement statement) {
                Map<String, DataSourceProperty> dataSourcePropertiesMap = null;
                ResultSet rs = null;
                try {
                    dataSourcePropertiesMap = new HashMap<>();
                    // DbConstant.DS_DB_SQL 为查询数据库中配置的多租户的数据源配置信息的SQL如
                    // "SELECT * FROM DATABASE_CONFIG "
              
                    rs = statement.executeQuery(DbConstant.DS_DB_SQL);
                    while (rs.next()) {
                        DataSourceProperty property = new DataSourceProperty();
                        String databaseCode = rs.getString(DbConstant.DatabaseConfigField.DATABASE_CODE);
                        property.setDriverClassName(rs.getString(DbConstant.DatabaseConfigField.DRIVER_CLASS));
                        property.setUrl(rs.getString(DbConstant.DatabaseConfigField.DATABASE_URL));
                        property.setUsername(rs.getString(DbConstant.DatabaseConfigField.USER_NAME));
                        property.setPassword(AESUtil.decrypt(rs.getString(DbConstant.DatabaseConfigField.USER_PASSWORD)));
                        property.setLazy(DS_DATASOURCE_LAZY);
                        // 设置Druid配置
                        String druidConfig = rs.getString(DbConstant.DatabaseConfigField.DRUID_CONFIG);
                        property.setDruid(getDruidConfig(druidConfig));
                        dataSourcePropertiesMap.put(databaseCode, property);
                    }
                } catch (SQLException e) {
                    log.error("查询DB数据源配置异常", e);
                } finally {
                    try {
                        if (rs != null) {
                            rs.close();
                        }
                    } catch (SQLException e) {
                        log.error("数据库ResultSet资源释放异常", e);
                    }
                    try {
                        statement.close();
                    } catch (SQLException e) {
                        log.error("数据库Statement资源释放异常", e);
                    }
                }
                log.info(">>>初始化加载DB库中数据源完成");
                return dataSourcePropertiesMap;
            }
        };
    }

自定义负载均衡策略

如下图slave组下有三个数据源,当用户使用slave切换数据源时会使用负载均衡算法。

系统自带了两个负载均衡算法

LoadBalanceDynamicDataSourceStrategy 轮询,是默认的。
RandomDynamicDataSourceStrategy 随机的。

spring:
  datasource:
    dynamic:
      datasource:
        master:
          username: sa
          password: ""
          url: jdbc:h2:mem:test
          driver-class-name: org.h2.Driver
          schema: db/schema.sql
        slave_1:
          username: sa
          password: ""
          url: jdbc:h2:mem:test
          driver-class-name: org.h2.Driver
        slave_2:
          username: sa
          password: ""
          url: jdbc:h2:mem:test
          driver-class-name: org.h2.Driver
        slave_3:
          username: sa
          password: ""
          url: jdbc:h2:mem:test
          driver-class-name: org.h2.Driver
      strategy: com.baomidou.dynamic.datasource.strategy.LoadBalanceDynamicDataSourceStrategy

如何自定义

如果默认的两个都不能满足要求,可以参考源码自定义。 暂时只能全局更改。

import java.util.List;
import java.util.concurrent.ThreadLocalRandom;
import javax.sql.DataSource;

public class RandomDynamicDataSourceStrategy implements DynamicDataSourceStrategy {
    public RandomDynamicDataSourceStrategy() {
    }

    public DataSource determineDataSource(List<DataSource> dataSources) {
        return (DataSource)dataSources.get(ThreadLocalRandom.current().nextInt(dataSources.size()));
    }
}

多数据源懒启动配置

懒启动:连接池创建出来后并不会立即初始化连接池,等需要使用connection的时候再初始化。

暂时只支持Druid和HikariCp和BeeCp连接池。

主要场景可能适合于数据源很多,又不需要启动立即初始化的情况,可以减少系统启动时间。

缺点在于,如果参数配置有误,则启动的时候不知道,初始化的时候失败,可能一直抛异常。

配置使用

spring:
  datasource:
    dynamic:
      primary: master #设置默认的数据源或者数据源组,默认值即为master
      strict: false #设置严格模式,默认false不启动. 启动后在未匹配到指定数据源时候会抛出异常,不启动则使用默认数据源.
      lazy: true #默认false非懒启动,系统加载到数据源立即初始化连接池
      datasource:
        master:
          url: jdbc:mysql://xx.xx.xx.xx:3306/dynamic
          username: root
          password: 123456
          driver-class-name: com.mysql.jdbc.Driver
          lazy: true #表示这个数据源懒启动
        db1:
          url: jdbc:mysql://xx.xx.xx.xx:3307/dynamic
          username: root
          password: 123456
          driver-class-name: com.mysql.jdbc.Driver
        db2:
          url: jdbc:mysql://xx.xx.xx.xx:3307/dynamic
          username: root
          password: 123456
          driver-class-name: com.mysql.jdbc.Driver

3. 参考资料

从3.4.0开始,可以注入多个DynamicDataSourceProvider的Bean以实现同时从多个不同来源加载数据源,注意同名会被覆盖。

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

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

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

相关文章

行军遇到各种复杂地形怎么处理?

行军遇到各种复杂地形怎么处理&#xff1f; 【安志强趣讲《孙子兵法》第30讲】 【原文】 凡军好高而恶下&#xff0c;贵阳而贱阴&#xff0c;养生而处实&#xff0c;军无百疾&#xff0c;是谓必胜。 【注释】 阳&#xff0c;太阳能照到的地方。阴&#xff0c;太阳照不到的地方。…

如何把DAYi-51开发板_做成?

DAYi-51开发板 1> 思维认知1.1> 凡是遇到卡壳&#xff0c;学不下去的情况&#xff0c;只有1个原因1.2> 什么叫掌握了&#xff1f;1.3> 深度练习1.4> 极度专注 2> 环境2.1> 大环境2.2> 贴身环境 3> 技术层面3.1> 找高手 1> 思维认知 1.1> 凡…

Redis之缓存和数据库双写一致方案讨论解读

目录 什么是缓存双写一致 更新缓存还是删除缓存&#xff1f; 先删除缓存,再更新数据库 场景描述 解决方案&#xff1a;延时双删策略 先更新数据库&#xff0c;再删除缓存 场景描述 解决方案&#xff1a;重试机制引入MQ ​编辑 什么是缓存双写一致 只要用缓存&#xf…

如何合并为pdf文件?合并为pdf文件的方法

在数字化时代&#xff0c;人们越来越依赖电子文档进行信息交流和存储。合并为PDF成为一种常见需求&#xff0c;它能将多个文档合而为一&#xff0c;方便共享和管理。无论是合并多个单页文档&#xff0c;还是将多页文档合并&#xff0c;操作都变得简单高效。那么。如何合并为pdf…

哈夫曼编码实现文件的压缩和解压

程序示例精选 哈夫曼编码实现文件的压缩和解压 如需安装运行环境或远程调试&#xff0c;见文章底部个人QQ名片&#xff0c;由专业技术人员远程协助&#xff01; 前言 这篇博客针对《哈夫曼编码实现文件的压缩和解压》编写代码&#xff0c;代码整洁&#xff0c;规则&#xff0…

【Sentinel】核心API-Entry与Context

文章目录 一、Entry1、Entry的声明2、使用API自定义资源3、基于SentinelResource注解标记资源 二、Context1、Context介绍2、Context的初始化3、AbstractSentinelInterceptor4、ContextUtil 一、Entry 1、Entry的声明 默认情况下&#xff0c;Sentinel会将controller中的方法作…

关于人工智能的担忧

人工智能的快速发展引发了一系列关于其潜在风险和担忧的讨论。以下是一些常见的人们对人工智能的担忧&#xff1a; 失业问题&#xff1a;人工智能的出现可能会导致很多工作岗位的消失&#xff0c;特别是那些需要重复性劳动的工作。人们担心机器取代人类工作将导致大规模失业和社…

W5500-EVB-PICO进行MQTT连接订阅发布教程(十二)

前言 上一章我们用开发板通过SNTP协议获取网络协议&#xff0c;本章我们介绍一下开发板通过配置MQTT连接到服务器上&#xff0c;并且订阅和发布消息。 什么是MQTT&#xff1f; MQTT是一种轻量级的消息传输协议&#xff0c;旨在在物联网&#xff08;IoT&#xff09;应用中实现设…

计算机毕业设计 社区买菜系统 Vue+SpringBoot+MySQL

作者主页&#xff1a;Designer 小郑 作者简介&#xff1a;Java全栈软件工程师一枚&#xff0c;来自浙江宁波&#xff0c;负责开发管理公司OA项目&#xff0c;专注软件前后端开发、系统定制、远程技术指导。CSDN学院、蓝桥云课认证讲师&#xff0c;全栈领域优质创作者。 项目内容…

JavaScript中的原型链(prototype chain)

聚沙成塔每天进步一点点 ⭐ 专栏简介⭐ JavaScript中的原型链⭐ 写在最后 ⭐ 专栏简介 前端入门之旅&#xff1a;探索Web开发的奇妙世界 记得点击上方或者右侧链接订阅本专栏哦 几何带你启航前端之旅 欢迎来到前端入门之旅&#xff01;这个专栏是为那些对Web开发感兴趣、刚刚踏…

如何访问GitHub

1、手动修改hosts 1.1、查找到最新的GitHub的hosts信息 通过链接&#xff1a;https://raw.hellogithub.com/hosts 进行查找最新的GitHub的hosts信息 1.2、查找到hosts文件位置 先找到 hosts 文件的位置&#xff0c;不同操作系统&#xff0c;hosts 文件的存储位置也不同&…

量化:基于RSRS的市场择时复现

文章目录 资源研报解读概念Q&ARSRS指标构建交易逻辑 资源 《阻力支撑相对强度RSRS研究报告》 链接&#xff1a;https://pan.baidu.com/s/1EhtoC25WSO7WpNiyZpcKYA 提取码&#xff1a;2023 合吾~~~祝投资顺利愉快&#xff01; 研报复现系列&#xff08;5&#xff09;基于阻力…

Dev-C++中,不使用include <string>也可以用string name1, name2; 为什么?

Dev-C中&#xff0c;不使用 include <string> 也可以用 string name1, name2; 为什么&#xff1f; 例如&#xff1a; #include <iostream> //#include <string> using namespace std; int main() { string s1, s2; cout << "请输入两个…

“深入探究SpringMVC的工作原理与入门实践“

目录 引言1. 什么是SpringMVC?1.1. 模型1.2. 视图1.3. 控制器 2. SpringMVC的工作流程2.1. 客户端发送请求2.2. DispatcherServlet的处理2.3. 处理器映射器的使用2.4. 处理器的执行2.5. 视图解析器的使用2.6. 视图的渲染 3. SpringMVC的核心组件4. 弹簧MVC总结 引言 SpringMV…

Java 多线程系列Ⅳ(单例模式+阻塞式队列+定时器+线程池)

多线程案例 一、设计模式&#xff08;单例模式工厂模式&#xff09;1、单例模式2、工厂模式 二、阻塞式队列1、生产者消费者模型2、阻塞对列在生产者消费者之间的作用3、用标准库阻塞队列实现生产者消费者模型4、模拟实现阻塞队列 三、定时器1、标准库中的定时器2、模拟实现定时…

WinXP 蓝屏死机,并报代码0x0000007B的错误

蓝屏死机&#xff0c;并报代码0x0000007B的错误&#xff0c;通常情况都是硬盘的存储控制器驱动加载错误导致故障。导致驱动加载错误的情况&#xff0c;可能有以下三种情况&#xff1a; 1、无法自动识别硬盘控制器 使用非正版的操作系统光盘&#xff08;进过修改或者加强的Wind…

doris多租户资源隔离及权限管理

Doris 的多租户和资源隔离方案&#xff0c;主要目的是为了多用户在同一 Doris 集群内进行数据操作时&#xff0c;减少相互之间的干扰&#xff0c;能够将集群资源更合理的分配给各用户。 该方案主要分为两部分&#xff0c;一是集群内节点级别的资源组划分&#xff0c;二是针对单…

明星录制祝福视频:传递温情与关怀的独特方式

在当今社交媒体和数字化时代&#xff0c;明星录制祝福视频已经成为一种新颖而独特的方式&#xff0c;用来表达温馨祝福、分享喜悦&#xff0c;或者为特殊的时刻增添一份特别的意义。无论是生日、结婚、毕业&#xff0c;还是节日、活动等&#xff0c;明星录制的祝福视频能够让人…

VUVLO电压监测器的工作原理、应用及性能分析 | 百能云芯

在现代电子设备中&#xff0c;电压监测是确保稳定性和可靠性的关键。VUVLO电压监测器是一种重要的电子元件&#xff0c;它的作用是监测电源电压&#xff0c;并在电压低于或高于设定值时触发相应的操作。在本文中&#xff0c;我们将深入探讨VUVLO电压监测器的工作原理、应用领域…

Windows下搭建MavLink通信协议环境,并用C++程序测试

搭建环境 git克隆 git clone https://github.com/mavlink/mavlink.git --recursive安装python的future库 pip install future使用可视化工具生成mavlink库 XML是选择消息格式&#xff0c;也可以自定义Out是输出路径Language是生成的语言&#xff0c;我这里是CProtocol是协议…