【mybatis-plus进阶】多租户场景中多数据源自定义来源dynamic-datasource实现
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. 基于此接口的抽象类实现
@Beanpublic 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()) {@Overrideprotected 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: sapassword: ""url: jdbc:h2:mem:testdriver-class-name: org.h2.Driverschema: db/schema.sqlslave_1:username: sapassword: ""url: jdbc:h2:mem:testdriver-class-name: org.h2.Driverslave_2:username: sapassword: ""url: jdbc:h2:mem:testdriver-class-name: org.h2.Driverslave_3:username: sapassword: ""url: jdbc:h2:mem:testdriver-class-name: org.h2.Driverstrategy: 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 #设置默认的数据源或者数据源组,默认值即为masterstrict: false #设置严格模式,默认false不启动. 启动后在未匹配到指定数据源时候会抛出异常,不启动则使用默认数据源.lazy: true #默认false非懒启动,系统加载到数据源立即初始化连接池datasource:master:url: jdbc:mysql://xx.xx.xx.xx:3306/dynamicusername: rootpassword: 123456driver-class-name: com.mysql.jdbc.Driverlazy: true #表示这个数据源懒启动db1:url: jdbc:mysql://xx.xx.xx.xx:3307/dynamicusername: rootpassword: 123456driver-class-name: com.mysql.jdbc.Driverdb2:url: jdbc:mysql://xx.xx.xx.xx:3307/dynamicusername: rootpassword: 123456driver-class-name: com.mysql.jdbc.Driver
3. 参考资料
从3.4.0开始,可以注入多个DynamicDataSourceProvider的Bean以实现同时从多个不同来源加载数据源,注意同名会被覆盖。
- dynamic-datasource GitHub 仓库 ↗:dynamic-datasource 的官方 GitHub 仓库,包含源代码、文档和示例等资源。
相关文章:
【mybatis-plus进阶】多租户场景中多数据源自定义来源dynamic-datasource实现
Springbootmybatis-plusdynamic-datasourceDruid 多租户场景中多数据源自定义来源dynamic-datasource实现 文章目录 Springbootmybatis-plusdynamic-datasourceDruid 多租户场景中多数据源自定义来源dynamic-datasource实现0.前言1. 作者提供了接口2. 基于此接口的抽象类实现自…...
vue3 async await
const getStruct async () > {//首先从store读取,否则通过接口获取if (store.state.struct.v ! null) {return store.state.struct.v;} else {const data await getStructApi();store.dispatch("struct/keepV", data).then(() > {console.log(&qu…...
CLion远程Linux开发环境搭建及找不到Linux头文件的解决方法
CLion远程开发环境搭建及找不到Linux头文件的解决方法 文章目录 CLion远程开发环境搭建及找不到Linux头文件的解决方法1.前言2.远程开发3.远程编译4.远程调试5.远程开发Linux头文件找不到(比如pthread.h、<sys/socket.h>)6.最后 1.前言 在某些时候…...
Python综合案例(基本地图使用)
一、基本地图的使用 基本代码: """ 演示地图可视化的基本使用 """ from pyecharts.charts import Map from pyecharts.options import VisualMapOpts# 准备地图对象 map Map() # 准备数据 data [("北京", 99),("…...
maven的scope总结
scope类型 compiletestprovidedruntimesystemimport compile 编译依赖范围。如果没有指定,就会默认使用该依赖范围。使用此依赖范围的Maven 依赖,对于编译、测试、运行三种classpath 都有效。大部分是这种,在编译、测试和运行的时候都需要使…...
Linux执行命令
命令格式 主命令 选项 参数(操作对象)例如: 修改主机名 hostname set-hostname 新名称显示/目录下的文件的详细信息 ls -l /命令 内置命令(builtin):shell程序自带的命令。 外部命令:有独立…...
Nginx 配置中root和alias的区别分析
root和alias都可以定义在location模块中,都是用来指定请求资源的真实路径,比如: location /i/ { root /data/w3; } 请求 http://foofish.net/i/top.gif 这个地址时,那么在服务器里面对应的真正的资源 是 /data/w3/i/top.gif文…...
AP51656 PWM和线性调光 LED车灯电源驱动IC 兼容替代PT4115 PT4205
产品描述 AP51656是一款连续电感电流导通模式的降压恒流源 用于驱动一颗或多颗串联LED 输入电压范围从 5V 到 60V,输出电流 可达 1.5A 。根据不同的输入电压和 外部器件, 可以驱动高达数十瓦的 LED。 内置功率开关,采用高端电流采样设置 …...
视频汇聚/视频云存储/视频监控管理平台EasyCVR部署后无法正常启用是什么问题?该如何解决?
安防监控/视频监控/视频汇聚平台EasyCVR能在复杂的网络环境中,将分散的各类视频资源进行统一汇聚、整合、集中管理,在视频监控播放上,视频云存储/安防监控汇聚平台EasyCVR支持多种播放协议,包括:HLS、HTTP-FLV、WebSoc…...
Kubernetes v1.25.0集群搭建实战案例(新版本含Docker容器运行时)
k8s 1.24之后弃用了docker容器运行时,安装方式上有所不同,网上找到的大多数都是1.24之前的版本。所以把自己搭建的完整过程记录下来供大家参考。 一、前言 k8s的部署方式有多种kubeadm、kind、minikube、Kubespray、kops等本文介绍官方推荐的kubeadm的…...
RabbitMQ、Kafka和RocketMQ比较
一、概述 消息队列中间件(MQ)是不同系统之间消息传递,异步通信的常见组件,RabbitMQ、Kafka和RocketMQ是目前业界常见的3种消息中间件,本文重点阐述了他们特性差异、架构设计和处理常见问题的方案。 二、特性比较 Ra…...
http和https区别,第三方证书如何保证服务器可信
HTTP(Hypertext Transfer Protocol)和HTTPS(HTTP Secure)是用于在客户端和服务器之间传输数据的协议,它们在以下几个方面有所区别: 安全性:HTTP是明文协议,数据在传输过程中不加密&…...
【内网穿透】使用Nodejs搭建简单的HTTP服务器 ,并实现公网远程访问
目录 前言 1.安装Node.js环境 2.创建node.js服务 3. 访问node.js 服务 4.内网穿透 4.1 安装配置cpolar内网穿透 4.2 创建隧道映射本地端口 5.固定公网地址 前言 Node.js 是能够在服务器端运行 JavaScript 的开放源代码、跨平台运行环境。Node.js 由 OpenJS Foundation…...
Linux中的多线程剖析
目录 1、前言 2、多线程理解 2.1 线程 2.2 通俗了解进程和线程 2.2.1 进程是资源分配的基本单位 2.2.2 Linux中的线程是一种轻量化进程 2.3 进程和线程详解 2.3.1 创建一个线程 (pthread_create) 2.3.2 线程自己的一部分数据 2.3.3 线程组 2.3.4 关于进程的其他操作…...
uniapp 集成蓝牙打印功能(个人测试佳博打印机)
uniapp 集成蓝牙打印功能(个人测试京博打印机) uniapp 集成蓝牙打印功能集成佳博内置的接口 uniapp 集成蓝牙打印功能 大家好今天分析的是uniapp 集成蓝牙打印功能,个人开发是app,应该是支持H5(没试过) 集成佳博内置的接口 下载dome地址&…...
pdf文件过大如何缩小上传?pdf压缩跟我学
在我们日常工作和生活中,经常会遇到PDF文件过大的问题,给文件传输和存储带来了很大的不便。那么,如何缩小PDF文件大小以便上传呢?下面就给大家分享几个压缩方法,一起来了解下PDF文件压缩方法吧~ 方法一:嗨格…...
设计模式之建造者模式与原型模式
目录 建造者模式 简介 使用场景 优缺点 模式结构 实现 原型模式 简介 应用场景 优缺点 模式结构 实现 建造者模式 简介 将复杂对象的构建与表示进行分离,使得同样的构建过程可以创建不同的表示。是一个将复杂的对象分解为多个简单的对象,然…...
合并到pdf怎么合并?这个方法了解一下
在现代数字化时代,PDF(便携式文档格式)已成为最常用的文件格式之一。PDF文件的优点在于其跨平台兼容性和保持文档格式不变的能力。然而,在某些情况下,我们可能需要知道合并到pdf。无论是为了方便管理、共享或者其他目的,本文将介绍…...
vue使用jsencrypt实现rsa前端加密
实现 RSA 加密 介绍 vue 完成 rsa 加密传输,jsencrypt 实现参数的前端加密 1 安装 jsencrypt npm install jsencrypt2 编写 jsencrypt.js 在 utils 文件夹中新建 jsencrypt.js 文件,内容如下:注意点:一般公钥都是后端生成好的&a…...
微波系统中散射参量S、阻抗参量Z及导纳参量Y之间的关系及MATLAB验证
微波系统中散射参量S、阻抗参量Z及导纳参量Y之间的关系及MATLAB验证 用HFSS设计了一微波元件,仿真出了其散射参量S、阻抗参量Z及导纳参量Y,用MATLAB验证他们之间的关系 HFSS设计螺旋线圈 用HFSS设计了一个螺旋线圈,如上图所示。 进行仿真&…...
变量 varablie 声明- Rust 变量 let mut 声明与 C/C++ 变量声明对比分析
一、变量声明设计:let 与 mut 的哲学解析 Rust 采用 let 声明变量并通过 mut 显式标记可变性,这种设计体现了语言的核心哲学。以下是深度解析: 1.1 设计理念剖析 安全优先原则:默认不可变强制开发者明确声明意图 let x 5; …...
[2025CVPR]DeepVideo-R1:基于难度感知回归GRPO的视频强化微调框架详解
突破视频大语言模型推理瓶颈,在多个视频基准上实现SOTA性能 一、核心问题与创新亮点 1.1 GRPO在视频任务中的两大挑战 安全措施依赖问题 GRPO使用min和clip函数限制策略更新幅度,导致: 梯度抑制:当新旧策略差异过大时梯度消失收敛困难:策略无法充分优化# 传统GRPO的梯…...
Android Wi-Fi 连接失败日志分析
1. Android wifi 关键日志总结 (1) Wi-Fi 断开 (CTRL-EVENT-DISCONNECTED reason3) 日志相关部分: 06-05 10:48:40.987 943 943 I wpa_supplicant: wlan0: CTRL-EVENT-DISCONNECTED bssid44:9b:c1:57:a8:90 reason3 locally_generated1解析: CTR…...
OpenLayers 可视化之热力图
注:当前使用的是 ol 5.3.0 版本,天地图使用的key请到天地图官网申请,并替换为自己的key 热力图(Heatmap)又叫热点图,是一种通过特殊高亮显示事物密度分布、变化趋势的数据可视化技术。采用颜色的深浅来显示…...
《用户共鸣指数(E)驱动品牌大模型种草:如何抢占大模型搜索结果情感高地》
在注意力分散、内容高度同质化的时代,情感连接已成为品牌破圈的关键通道。我们在服务大量品牌客户的过程中发现,消费者对内容的“有感”程度,正日益成为影响品牌传播效率与转化率的核心变量。在生成式AI驱动的内容生成与推荐环境中࿰…...
el-switch文字内置
el-switch文字内置 效果 vue <div style"color:#ffffff;font-size:14px;float:left;margin-bottom:5px;margin-right:5px;">自动加载</div> <el-switch v-model"value" active-color"#3E99FB" inactive-color"#DCDFE6"…...
【Web 进阶篇】优雅的接口设计:统一响应、全局异常处理与参数校验
系列回顾: 在上一篇中,我们成功地为应用集成了数据库,并使用 Spring Data JPA 实现了基本的 CRUD API。我们的应用现在能“记忆”数据了!但是,如果你仔细审视那些 API,会发现它们还很“粗糙”:有…...
优选算法第十二讲:队列 + 宽搜 优先级队列
优选算法第十二讲:队列 宽搜 && 优先级队列 1.N叉树的层序遍历2.二叉树的锯齿型层序遍历3.二叉树最大宽度4.在每个树行中找最大值5.优先级队列 -- 最后一块石头的重量6.数据流中的第K大元素7.前K个高频单词8.数据流的中位数 1.N叉树的层序遍历 2.二叉树的锯…...
python报错No module named ‘tensorflow.keras‘
是由于不同版本的tensorflow下的keras所在的路径不同,结合所安装的tensorflow的目录结构修改from语句即可。 原语句: from tensorflow.keras.layers import Conv1D, MaxPooling1D, LSTM, Dense 修改后: from tensorflow.python.keras.lay…...
用机器学习破解新能源领域的“弃风”难题
音乐发烧友深有体会,玩音乐的本质就是玩电网。火电声音偏暖,水电偏冷,风电偏空旷。至于太阳能发的电,则略显朦胧和单薄。 不知你是否有感觉,近两年家里的音响声音越来越冷,听起来越来越单薄? —…...
