【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设计了一个螺旋线圈,如上图所示。 进行仿真&…...

Linux应用开发之网络套接字编程(实例篇)
服务端与客户端单连接 服务端代码 #include <sys/socket.h> #include <sys/types.h> #include <netinet/in.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <arpa/inet.h> #include <pthread.h> …...

【OSG学习笔记】Day 18: 碰撞检测与物理交互
物理引擎(Physics Engine) 物理引擎 是一种通过计算机模拟物理规律(如力学、碰撞、重力、流体动力学等)的软件工具或库。 它的核心目标是在虚拟环境中逼真地模拟物体的运动和交互,广泛应用于 游戏开发、动画制作、虚…...

K8S认证|CKS题库+答案| 11. AppArmor
目录 11. AppArmor 免费获取并激活 CKA_v1.31_模拟系统 题目 开始操作: 1)、切换集群 2)、切换节点 3)、切换到 apparmor 的目录 4)、执行 apparmor 策略模块 5)、修改 pod 文件 6)、…...

盘古信息PCB行业解决方案:以全域场景重构,激活智造新未来
一、破局:PCB行业的时代之问 在数字经济蓬勃发展的浪潮中,PCB(印制电路板)作为 “电子产品之母”,其重要性愈发凸显。随着 5G、人工智能等新兴技术的加速渗透,PCB行业面临着前所未有的挑战与机遇。产品迭代…...
k8s从入门到放弃之Ingress七层负载
k8s从入门到放弃之Ingress七层负载 在Kubernetes(简称K8s)中,Ingress是一个API对象,它允许你定义如何从集群外部访问集群内部的服务。Ingress可以提供负载均衡、SSL终结和基于名称的虚拟主机等功能。通过Ingress,你可…...

Docker 运行 Kafka 带 SASL 认证教程
Docker 运行 Kafka 带 SASL 认证教程 Docker 运行 Kafka 带 SASL 认证教程一、说明二、环境准备三、编写 Docker Compose 和 jaas文件docker-compose.yml代码说明:server_jaas.conf 四、启动服务五、验证服务六、连接kafka服务七、总结 Docker 运行 Kafka 带 SASL 认…...
Qt Widget类解析与代码注释
#include "widget.h" #include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget) {ui->setupUi(this); }Widget::~Widget() {delete ui; }//解释这串代码,写上注释 当然可以!这段代码是 Qt …...

使用分级同态加密防御梯度泄漏
抽象 联邦学习 (FL) 支持跨分布式客户端进行协作模型训练,而无需共享原始数据,这使其成为在互联和自动驾驶汽车 (CAV) 等领域保护隐私的机器学习的一种很有前途的方法。然而,最近的研究表明&…...
Frozen-Flask :将 Flask 应用“冻结”为静态文件
Frozen-Flask 是一个用于将 Flask 应用“冻结”为静态文件的 Python 扩展。它的核心用途是:将一个 Flask Web 应用生成成纯静态 HTML 文件,从而可以部署到静态网站托管服务上,如 GitHub Pages、Netlify 或任何支持静态文件的网站服务器。 &am…...
spring:实例工厂方法获取bean
spring处理使用静态工厂方法获取bean实例,也可以通过实例工厂方法获取bean实例。 实例工厂方法步骤如下: 定义实例工厂类(Java代码),定义实例工厂(xml),定义调用实例工厂ÿ…...