当前位置: 首页 > news >正文

mybatisplus多租户原理略解

概述

当前mybatisPlus版本

<dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.5.3.2</version>
</dependency>

jdk版本:17
springboot版本:

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-dependencies</artifactId><version>3.1.2</version>
</dependency>

业务中想按照租户划分权限时,一般简单的就是在表里加个字段,但是这样每个sql语句都要改造,很不方便。

mybatisplus有个现成的租户插件
com.baomidou.mybatisplus.extension.plugins.inner.TenantLineInnerInterceptor
在配置租户插件之前,需要在token中先塞入租户id,方便后面在拦截器中获取当前用户的租户.

租户注入的关键代码在
com.baomidou.mybatisplus.extension.plugins.inner.TenantLineInnerInterceptor#buildTableExpression
在这里插入图片描述

配置

配置的时候租户拦截器需要放在第一个,即`index=0

package org.qps.common.tenant.handle;import cn.hutool.core.collection.ListUtil;
import com.baomidou.mybatisplus.extension.plugins.handler.TenantLineHandler;
import org.qps.common.core.utils.StringUtils;
import org.qps.common.satoken.utils.LoginHelper;
import org.qps.common.tenant.helper.TenantHelper;
import org.qps.common.tenant.properties.TenantProperties;
import lombok.AllArgsConstructor;
import net.sf.jsqlparser.expression.Expression;
import net.sf.jsqlparser.expression.NullValue;
import net.sf.jsqlparser.expression.StringValue;import java.util.List;/*** 自定义租户处理器**/
@AllArgsConstructor
public class PlusTenantLineHandler implements TenantLineHandler {private final TenantProperties tenantProperties;@Overridepublic Expression getTenantId() {String tenantId = LoginHelper.getTenantId();if (StringUtils.isBlank(tenantId)) {return new NullValue();}String dynamicTenantId = TenantHelper.getDynamic();if (StringUtils.isNotBlank(dynamicTenantId)) {// 返回动态租户return new StringValue(dynamicTenantId);}// 返回固定租户return new StringValue(tenantId);}@Overridepublic boolean ignoreTable(String tableName) {String tenantId = LoginHelper.getTenantId();// 判断是否有租户if (StringUtils.isNotBlank(tenantId)) {// 不需要过滤租户的表List<String> excludes = tenantProperties.getExcludes();// 非业务表List<String> tables = ListUtil.toList("gen_table","gen_table_column");tables.addAll(excludes);return tables.contains(tableName);}return true;}}package org.qps.common.tenant.config;import cn.dev33.satoken.dao.SaTokenDao;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.InnerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.TenantLineInnerInterceptor;
import org.qps.common.core.utils.reflect.ReflectUtils;
import org.qps.common.mybatis.config.MybatisPlusConfig;
import org.qps.common.redis.config.RedisConfig;
import org.qps.common.redis.config.properties.RedissonProperties;
import org.qps.common.tenant.core.TenantSaTokenDao;
import org.qps.common.tenant.handle.PlusTenantLineHandler;
import org.qps.common.tenant.handle.TenantKeyPrefixHandler;
import org.qps.common.tenant.manager.TenantSpringCacheManager;
import org.qps.common.tenant.properties.TenantProperties;
import org.redisson.config.ClusterServersConfig;
import org.redisson.config.SingleServerConfig;
import org.redisson.spring.starter.RedissonAutoConfigurationCustomizer;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cache.CacheManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Primary;import java.util.ArrayList;
import java.util.List;/*** 租户配置类** TenantProperties 自定义租户配置对象* MybatisPlusConfig 自定义mybatisPlus配置,维护了分页拦截器等基础拦截器*/
@EnableConfigurationProperties(TenantProperties.class)
@AutoConfiguration(after = {MybatisPlusConfig.class})
@ConditionalOnProperty(value = "tenant.enable", havingValue = "true")
public class TenantConfig {/*** 初始化租户配置*/@Beanpublic boolean tenantInit(MybatisPlusInterceptor mybatisPlusInterceptor,TenantProperties tenantProperties) {List<InnerInterceptor> interceptors = new ArrayList<>();// 多租户插件 必须放到第一位interceptors.add(tenantLineInnerInterceptor(tenantProperties));interceptors.addAll(mybatisPlusInterceptor.getInterceptors());mybatisPlusInterceptor.setInterceptors(interceptors);return true;}/*** 多租户插件*/public TenantLineInnerInterceptor tenantLineInnerInterceptor(TenantProperties tenantProperties) {return new TenantLineInnerInterceptor(new PlusTenantLineHandler(tenantProperties));}}

多租户拦截忽略

启用多租户之后,有些业务sql想查询多个租户的数据或者不想被注入租户id。

那么可以加上com.baomidou.mybatisplus.annotation.InterceptorIgnore
@InterceptorIgnore(tenantLine = "true")
即可忽略

原理可以参考源码
com.baomidou.mybatisplus.extension.plugins.inner.TenantLineInnerInterceptor#beforeQuery

com.baomidou.mybatisplus.core.plugins.InterceptorIgnoreHelper#willIgnoreTenantLine

com.baomidou.mybatisplus.core.plugins.InterceptorIgnoreHelper#willIgnore

将注解数据初始化到内存中
com.baomidou.mybatisplus.core.plugins.InterceptorIgnoreHelper#initSqlParserInfoCache(java.lang.Class<?>)

相关文章:

mybatisplus多租户原理略解

概述 当前mybatisPlus版本 <dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.5.3.2</version> </dependency>jdk版本&#xff1a;17 springboot版本&#xff1a;…...

Spring整合RabbitMQ-配制文件方式-1-消息生产者

Spring-amqp是对AMQP的一些概念的一些抽象&#xff0c;Spring-rabbit是对RabbitMQ操作的封装实现。 主要有几个核心类RabbitAdmin、RabbitTemplate、SimpleMessageListenerContainer等 RabbitAdmin类完成对Exchange、Queue、Binding的操作&#xff0c;在容器中管理 了RabbitA…...

Python Opencv实践 - 凸包检测(ConvexHull)

import cv2 as cv import numpy as np import matplotlib.pyplot as pltimg cv.imread("../SampleImages/stars.png") plt.imshow(img[:,:,::-1])img_contour img.copy() #得到灰度图做Canny边缘检测 img_gray cv.cvtColor(img_contour, cv.COLOR_BGR2GRAY) edges…...

IP网络广播系统有哪些优点

IP网络广播系统有哪些优点 IP网络广播系统有哪些优点&#xff1f; IP网络广播系统是基于 TCP/IP 协议的公共广播系统&#xff0c;采用 IP 局域网或 广域网作为数据传输平台&#xff0c;扩展了公共广播系统的应用范围。随着局域网络和 网络的发展 , 使网络广播的普及变为可能 …...

【LeetCode】83. 删除排序链表中的重复元素

83. 删除排序链表中的重复元素&#xff08;简单&#xff09; 方法&#xff1a;一次遍历 思路 由于给定的链表是排好序的&#xff0c;因此重复的元素在链表中出现的位置是连续的&#xff0c;因此我们只需要对链表进行一次遍历&#xff0c;就可以删除重复的元素。 从指针 cur 指…...

【大数据】Flink 详解(七):源码篇 Ⅱ

本系列包含&#xff1a; 【大数据】Flink 详解&#xff08;一&#xff09;&#xff1a;基础篇【大数据】Flink 详解&#xff08;二&#xff09;&#xff1a;核心篇 Ⅰ【大数据】Flink 详解&#xff08;三&#xff09;&#xff1a;核心篇 Ⅱ【大数据】Flink 详解&#xff08;四…...

stable diffusion实践操作-SD原理

系列文章目录 本文专门开一节写SD原理相关的内容&#xff0c;在看之前&#xff0c;可以同步关注&#xff1a; stable diffusion实践操作 文章目录 系列文章目录前言一、原理说明1.1、出图原理1.1.1 AI画画不是和人一样&#xff0c;从0开始&#xff0c;而是一个去噪点的过程&am…...

C++ Primer Plus第十三章编程练习答案

1&#xff0c;以下面的类声明为基础: // base class class Cd{ // represents a CD disk private: char performers[50] ; char label[20]; int selections;// number of selections double playtime; // playing time in minutes public: Cd(char * sl,char * s2,int n,double…...

Elasticsearch:wildcard - 通配符搜索

Elasticsearch 是一个分布式、免费和开放的搜索和分析引擎&#xff0c;适用于所有类型的数据&#xff0c;例如文本、数字、地理空间、结构化和非结构化数据。 它基于 Apache Lucene 构建&#xff0c;Apache Lucene 是一个全文搜索引擎&#xff0c;可用于各种编程语言。 由于其速…...

配置类安全问题学习小结

目录 一、前言 二、漏洞类型 目录 一、前言 二、漏洞类型 2.1 Strict Transport Security Not Enforced 2.2 SSL Certificate Cannot Be Trusted 2.3 SSL Anonymous Cipher Suites Supported 2.4 "Referrer Policy”Security 头值不安全 2.5 “Content-Security-…...

IMX6ULL移植篇-uboot源码目录

一. uboot 源码分析前提 由于 uboot 会使用到一些经过编译才会生成的文件&#xff0c;因此&#xff0c;我们在分析 uboot的时候&#xff0c;需要先编译一下 uboot 源码工程。 这里所用的开发板是 nand-flash版本。 二. uboot 源码目录及编译 1. uboot 源码目录 uboot源码目…...

SAP MM学习笔记27- 购买依赖(采购申请)

前面已经努力的学习了 购买发注&#xff0c;入库&#xff0c;请求书照合 等功能&#xff0c;还是蛮多内容的哈。 剩下的功能&#xff0c;比如 右侧的 所要量决定&#xff0c;供给元决定&#xff0c;仕入先选择 还没学。 从这章开始&#xff0c;要开始学习它们了。 这一章先来…...

C++零碎记录(八)

14. 运算符重载简介 14.1 运算符重载简介 ① 运算符重载&#xff1a;对已有的运算符重新进行定义&#xff0c;赋予其另一种功能&#xff0c;以适应不同的数据类型。 ② 对于内置的数据类型的表达式的运算符是不可能改变的。 14.2 加号运算符重载 ① 加号运算符作用&#x…...

基于matlab的扩频解扩误码率完整程序分享

clc; clear; close all; warning off; addpath(genpath(pwd)); r5; N2^r-1;%周期31 aones(1,r); mzeros(1,N); for i1:(2^r-1) temp mod((a(5)a(2)),2); for jr:-1:2 a(j)a(j-1); end a(1)temp; m(i)a(r); end mm*2-1;%双极性码 %产生随…...

算法:轮转数组---循环取模运算

1、题目&#xff1a; 给定一个整数数组 nums&#xff0c;将数组中的元素向右轮转 k 个位置&#xff0c;其中 k 是非负数。 2、分析特点&#xff1a; 轮转 > 取模运算 我们可以使用额外的数组来将每个元素放至正确的位置。用 n 表示数组的长度&#xff0c;我们遍历原数组&a…...

Vue教程

官网vue快速上手 vue示例图 请点击下面工程名称&#xff0c;跳转到代码的仓库页面&#xff0c;将工程 下载下来 Demo Code 里有详细的注释 代码&#xff1a;LearnVue...

算法之双指针题型:

双指针例题小总结&#xff1a; 力扣27&#xff1a; 移除元素 力扣题目链接 双指针分为&#xff1a; 快慢双指针&#xff1a;同一个起点&#xff0c;同向出发 相向双指针&#xff1a;从两端出发&#xff0c;方向相反&#xff0c;终会相遇 经典的双指针&#xff08;快慢双指…...

vue传递给后端时间格式问题

前端处理 首先前端使用moment.js进行处理 data.userEnrolDate moment(data.userEnrolDate).format(YYYY-MM-DD HH:mm:ss);后端处理 JsonFormat(timezone "GMT8", pattern "yyyy-MM-dd HH:mm:ss") DateTimeFormat(pattern "yyyy-MM-dd HH:mm:ss…...

php使用jwt作登录验证

1 在项目根目录下&#xff0c;安装jwt composer require firebase/php-jwt 2 在登录控制器中加入生成token的代码 use Firebase\JWT\JWT; use Firebase\JWT\Key; class Login extends Cross {/*** 显示资源列表** return \think\Response*/public function index(Request $r…...

【zlm】 PTS DTS

在音视频编码和传输中&#xff0c;PTS&#xff08;Presentation Time Stamp&#xff09;和DTS&#xff08;Decoding Time Stamp&#xff09;是两个关键的时间戳&#xff0c;用于确保音视频帧的顺序和同步。它们在多媒体处理中扮演重要的角色&#xff1a; PTS&#xff08;Presen…...

KubeSphere 容器平台高可用:环境搭建与可视化操作指南

Linux_k8s篇 欢迎来到Linux的世界&#xff0c;看笔记好好学多敲多打&#xff0c;每个人都是大神&#xff01; 题目&#xff1a;KubeSphere 容器平台高可用&#xff1a;环境搭建与可视化操作指南 版本号: 1.0,0 作者: 老王要学习 日期: 2025.06.05 适用环境: Ubuntu22 文档说…...

脑机新手指南(八):OpenBCI_GUI:从环境搭建到数据可视化(下)

一、数据处理与分析实战 &#xff08;一&#xff09;实时滤波与参数调整 基础滤波操作 60Hz 工频滤波&#xff1a;勾选界面右侧 “60Hz” 复选框&#xff0c;可有效抑制电网干扰&#xff08;适用于北美地区&#xff0c;欧洲用户可调整为 50Hz&#xff09;。 平滑处理&…...

【JavaSE】绘图与事件入门学习笔记

-Java绘图坐标体系 坐标体系-介绍 坐标原点位于左上角&#xff0c;以像素为单位。 在Java坐标系中,第一个是x坐标,表示当前位置为水平方向&#xff0c;距离坐标原点x个像素;第二个是y坐标&#xff0c;表示当前位置为垂直方向&#xff0c;距离坐标原点y个像素。 坐标体系-像素 …...

稳定币的深度剖析与展望

一、引言 在当今数字化浪潮席卷全球的时代&#xff0c;加密货币作为一种新兴的金融现象&#xff0c;正以前所未有的速度改变着我们对传统货币和金融体系的认知。然而&#xff0c;加密货币市场的高度波动性却成为了其广泛应用和普及的一大障碍。在这样的背景下&#xff0c;稳定…...

SQL慢可能是触发了ring buffer

简介 最近在进行 postgresql 性能排查的时候,发现 PG 在某一个时间并行执行的 SQL 变得特别慢。最后通过监控监观察到并行发起得时间 buffers_alloc 就急速上升,且低水位伴随在整个慢 SQL,一直是 buferIO 的等待事件,此时也没有其他会话的争抢。SQL 虽然不是高效 SQL ,但…...

【C++进阶篇】智能指针

C内存管理终极指南&#xff1a;智能指针从入门到源码剖析 一. 智能指针1.1 auto_ptr1.2 unique_ptr1.3 shared_ptr1.4 make_shared 二. 原理三. shared_ptr循环引用问题三. 线程安全问题四. 内存泄漏4.1 什么是内存泄漏4.2 危害4.3 避免内存泄漏 五. 最后 一. 智能指针 智能指…...

day36-多路IO复用

一、基本概念 &#xff08;服务器多客户端模型&#xff09; 定义&#xff1a;单线程或单进程同时监测若干个文件描述符是否可以执行IO操作的能力 作用&#xff1a;应用程序通常需要处理来自多条事件流中的事件&#xff0c;比如我现在用的电脑&#xff0c;需要同时处理键盘鼠标…...

HubSpot推出与ChatGPT的深度集成引发兴奋与担忧

上周三&#xff0c;HubSpot宣布已构建与ChatGPT的深度集成&#xff0c;这一消息在HubSpot用户和营销技术观察者中引发了极大的兴奋&#xff0c;但同时也存在一些关于数据安全的担忧。 许多网络声音声称&#xff0c;这对SaaS应用程序和人工智能而言是一场范式转变。 但向任何技…...

适应性Java用于现代 API:REST、GraphQL 和事件驱动

在快速发展的软件开发领域&#xff0c;REST、GraphQL 和事件驱动架构等新的 API 标准对于构建可扩展、高效的系统至关重要。Java 在现代 API 方面以其在企业应用中的稳定性而闻名&#xff0c;不断适应这些现代范式的需求。随着不断发展的生态系统&#xff0c;Java 在现代 API 方…...

Vue ③-生命周期 || 脚手架

生命周期 思考&#xff1a;什么时候可以发送初始化渲染请求&#xff1f;&#xff08;越早越好&#xff09; 什么时候可以开始操作dom&#xff1f;&#xff08;至少dom得渲染出来&#xff09; Vue生命周期&#xff1a; 一个Vue实例从 创建 到 销毁 的整个过程。 生命周期四个…...