mybatis-plus 多租户方案1使用和坑注意事项,方案是需要实现租户功能的表都增加租户id字段

1 前提springboot整合好 mybatis-plus (版本3.5.4)
   需要实现多租户的表,添加修改对应字段和 pojo类 (表添加tenant_id字段,pojo添加tenantId属性)

配置文件更改,方便扩展

#多租户配置
tenant:enable: truecolumn: tenant_idignoreTables:- tb_order- users

属性文件配置类

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import java.util.List;/*** 多租户配置属性类*/
@Component
@Data
@ConfigurationProperties(prefix = "tenant")
public class TenantProperties {/*** 是否开启多租户*/private Boolean enable;/*** 租户id字段名*/private String column;/*** 需要忽略的多租户的表,此配置优先filterTables,若此配置为空则启用filterTables*/private List<String> ignoreTables;}

4 租户id管理类,从threadlocal 中取,这个根据业务情况来

/*** 租户上下文持有者,用于管理当前线程的租户ID。* 提供了获取、设置和清除当前线程租户ID的方法。*/
public class TenantContextHolder {// 静态ThreadLocal变量,用于存储当前线程的租户IDstatic ThreadLocal<Long> tenantThreadLocal = new ThreadLocal<>();/*** 获取当前线程的租户ID。** @return 当前线程的租户ID*/public static Long getCurrentTenantId() {return tenantThreadLocal.get();}/*** 设置当前线程的租户ID。** @param tenantId 要设置的租户ID*/public static void setCurrentTenantId(Long tenantId) {tenantThreadLocal.set(tenantId);}/*** 清除当前线程的租户ID,使得线程不再关联任何租户。*/public static void clear() {tenantThreadLocal.remove();}
}

多租户处理器实现,核心类

import com.baomidou.mybatisplus.extension.plugins.handler.TenantLineHandler;
import net.sf.jsqlparser.expression.Expression;
import net.sf.jsqlparser.expression.LongValue;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;import java.util.List;/*** 多租户处理器实现,核心类*/
@Component
public class MultiTenantHandler implements TenantLineHandler {@Autowiredprivate TenantProperties tenantProperties;/*** 根据表名判断是否忽略拼接多租户条件* 默认都要进行解析并拼接多租户条件** @param tableName 表名* @return 是否忽略, true:表示忽略,false:需要解析并拼接多租户条件*/@Overridepublic boolean ignoreTable(String tableName) {//忽略指定表对租户数据的过滤List<String> ignoreTables = tenantProperties.getIgnoreTables();if (null != ignoreTables && ignoreTables.contains(tableName)) {return true;}return false;}/*** 获取租户ID值表达式,只支持单个ID值 (实际应该从用户信息中获取)* @return 租户ID值表达式*/@Overridepublic Expression getTenantId() {if(TenantContextHolder.getCurrentTenantId()!=null){Long tenantId = TenantContextHolder.getCurrentTenantId();if(tenantId!=null){return new LongValue(tenantId);}}//设默认的值 或 异常,灵活处理return new LongValue(0);}/*** 获取租户字段名,默认字段名叫: tenant_id* @return 租户字段名*/@Overridepublic String getTenantIdColumn() {return tenantProperties.getColumn();}}

mybatis 拦截器配置,核心类

import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.BlockAttackInnerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.TenantLineInnerInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Configuration
public class MybatisPlusConfig {@Autowiredprivate MultiTenantHandler tenantHandler;@Autowiredprivate TenantProperties tenantProperties;@Beanpublic MybatisPlusInterceptor mybatisPlusInterceptor() {MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();if (tenantProperties.getEnable()) {// 添加多租户插件interceptor.addInnerInterceptor(new TenantLineInnerInterceptor(tenantHandler));}//分页插件interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));//防止全表更新与删除插件: BlockAttackInnerInterceptorBlockAttackInnerInterceptor blockAttackInnerInterceptor = new BlockAttackInnerInterceptor();interceptor.addInnerInterceptor(blockAttackInnerInterceptor);return interceptor;}
}

不需要租户的方法 (此注解只能放在mapper层的接口方法中),可以添加 如下配置,如,生成的sql就不会拼接租户的字段

@InterceptorIgnore(tenantLine = "true")
List<Book> searchAllBook_diySql();

写个springboot 拦截器或用其它方案,如拦截器里,将header中的租户id,设置到TenantContextHolder.setCurrentTenantId里面去

开始测试,需要使用租户功能的,在header中添加 租户id
在增删改查操作时,sql都会拼接上 租户id的条件



坑坑坑坑坑坑坑坑坑坑坑坑坑坑坑坑坑坑坑坑


1 自己写的sql ,不要加租户id字段,不要加租户id字段,不要加租户id字段,系统会自己拼接sql

这个示例,租户id都是统一添加在header中,拦截器再从header中取租户id,并设置到TenantContextHolder.setCurrentTenantId里面去,某些方法又在参数里如 requestParam或RequestBody中设置了租户id,会引发数据错乱,这边是使用了一个aop拦截器,将参数中传递的租户id,统一设为null,如下

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;
import java.lang.reflect.Field;@Aspect
@Component
public class TenantIdAspect {@Before("execution(* cn.baidu.sharding_jdbc_test.control..*.*(..)) && args(*)")public void cleanTenantId(JoinPoint joinPoint) {Object[] args = joinPoint.getArgs();for (Object arg : args) {// 使用反射来设置租户ID为nullif (arg != null) {try {String fieldname = "tenantId"; // 假设所有实体类中租户ID的字段名为tenantIdField field = arg.getClass().getDeclaredField(fieldname);field.setAccessible(true);field.set(arg, null);} catch (NoSuchFieldException | IllegalAccessException e) {// 处理异常,例如记录日志e.printStackTrace();}}}}
}

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

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

相关文章

【Java】网制焦,实也难,0基础,学反射

【Java】网制焦&#xff0c;实也难&#xff0c;0基础&#xff0c;学反射 文章目录 【Java】网制焦&#xff0c;实也难&#xff0c;0基础&#xff0c;学反射反射的概述 获取Class对象的三种方式通过对象的getClass()方法通过类的静态属性class通过Class.forName()方法 通过反射获…

代码随想录算法训练营第三十三天|LeetCode1005 k次取反后最大化的数组和、LeetCode134 加油站

题1&#xff1a; 指路&#xff1a;1005. K 次取反后最大化的数组和 - 力扣&#xff08;LeetCode&#xff09; 思路与代码&#xff1a; 题意清晰&#xff0c;需要注意的是需要把k次机会用完。数组中的数分为三种情况&#xff1a;正数&#xff0c;负数&#xff0c;0。要求数组…

《平凡的世界》读后感:走进平凡的世界

《平凡的世界》是一部充满人性光辉的小说&#xff0c;通过描写普通人的生活&#xff0c;展现了人生的苦乐交织。这篇读后感旨在通过秀、少平、金秀、兰香、秀莲、少安、孙玉厚、孙玉亭、顾养民、润生、润叶、向前、登云、晓霞、田福堂、田福军、张有智、苗凯、王满银、兰花等人…

算法 | 子集数排列树满m叉树二分搜索归并排序快速排序

子集树&#xff1a;O(2^n) 一个序列的所有子集为2^n&#xff0c;即可看成具有2^n个叶节点的满二叉树 int backtrack(int k) //k表示扩展结点在解空间树中所处的层次 {if(k>n) //n标识问题的规模output(x); //x是存放当前解的一维数组if(constraint(k)…

01—Linux网络设置

1.1查看及测试网络 1.1.1 查看网络配置 1.查看网络接口地址 主机的网络接口卡通常称为网络接口。在LInux操作系统中&#xff0c;使用ifconfig命令可以查看网络接口的地址配置信息。 &#xff08;1&#xff09;查看活动的网络接口设备 若采用mini版CenOS7安装的系统&#x…

新技术前沿-2023-大模型学习根据个人数据集微调一个Transformer模型

参考如何根据自己的数据集微调一个 Transformer 模型 我们将通过NLP中最常见的文本分类任务来学习如何在自己的数据集上利用迁移学习(transfer learning)微调一个预训练的Transformer模型——DistilBERT。DistilBERT是BERT的一个衍生版本&#xff0c;它的优点在它的性能与BERT相…

Vue14-监视属性

一、天气案例 1-1、方式一&#xff1a;{{三目运算符}} 1-2、方式二&#xff1a;计算属性 1-3、方式三&#xff1a;click中写简单逻辑 click里面可以写简单的逻辑语句。不用this 解决方式&#xff1a; 小结&#xff1a; 绑定事件的时候&#xff0c;xxx"yyy" xxx&…

C语言学习系列:GCC编译器Windows版本MinGW-w64的安装教程

本文图文分享如何安装C语言编译器——MinGW-w64。 只要看到这篇文章&#xff0c;就可以按照文中步骤正确安装MinGW-w64并使用。 一、什么是 MinGW-w64 &#xff1f; 我们知道C语言是高级语言&#xff0c;必须编译为二进制文件&#xff0c;才能为计算机运行&#xff0c;MinGW…

Web前端Canvas教程:绘制图形、动画与交互的奇妙世界

Web前端Canvas教程&#xff1a;绘制图形、动画与交互的奇妙世界 在Web前端技术中&#xff0c;Canvas无疑是一个强大的工具&#xff0c;它允许开发者在网页上绘制复杂的图形、创建生动的动画&#xff0c;并实现丰富的交互效果。本文将带领你走进Canvas的奇妙世界&#xff0c;从…

理解我的积木编程思想

1 学习教程&#xff0c;至少7139手册2 编程实践&#xff0c;遇到实际问题后&#xff0c;在技术资料中查找关键词3 选择适合的条目找到代 码。修正&#xff0c;组合。

[发布]嵌入式系统远程测控软件-基于Qt

目录 一. 引言二. 软件功能2.1 原理2.2 软件功能2.3 运行环境 三. 软件操作使用3.1 软件界面3.2 软件功能使用详解3.2.1 连接3.2.2 数据监测3.2.3 数据修改3.2.4 数据保存 3.3 软件的硬件连接 四. 通信协议——STM32移植篇4.1 通信协议4.2 STM32如何传输浮点数4.3 简单移植&…

shell编程(三)—— 控制语句

程序的运行除了顺序运行外&#xff0c;还可以通过控制语句来改变执行顺序。本文介绍bash的控制语句用法。 一、条件语句 Bash 中的条件语句让我们可以决定一个操作是否被执行。结果取决于一个包在[[ ]]里的表达式。 bash中的检测命令由[[]]包起来&#xff0c;用于检测一个条…

第一次视频学习

1、了解AI答题应用 1.1 业务流程架构图 1.2 自定义上传题目流程 1.3 时序图 这个比较困难&#xff0c;第一次了解到流式&#xff0c;便于前端与用户交互

千益畅行,引领旅游新潮流,共享经济下的创新旅游模式

在当前旅游行业中&#xff0c;千益畅行作为一种新型的旅游模式&#xff0c;正逐渐受到市场的关注和认可。它不仅为旅行社带来了新的客流&#xff0c;还巧妙地规避了高额的广告费用&#xff0c;实现了资源配置的优化和营销成本的大幅节约。 面对旅游经济的下滑&#xff0c;许多…

【微服务】springcloud-alibaba 配置多环境管理使用详解

目录 一、前言 二、配置多环境问题概述 2.1 什么是微服务多环境配置管理 2.1.1 微服务多环境配置管理问题起源 2.2 为什么要做多环境配置管理 2.3 微服务多环境配置管理解决方案 三、springboot 配置多环境管理解决方案 3.1 前置准备 3.1.1 搭建一个springboot工程 3.…

【PowerDesigner】创建和管理CDM之使用实体间关系

目录 &#x1f30a;1. PowerDesigner简介 &#x1f30d;1.1 常用模型文件 &#x1f30d;1.2 PowerDesigner使用环境 &#x1f30a;2. 创建和管理CDM &#x1f30d;​​​​​​2.1 新建CDM &#x1f30d;2.2 使用实体间关系 &#x1f30c;a. 使用联系 &#x1f30c;b. …

C#面:PDB是什么东西? 在调试中它应该放在哪里

C# PDB&#xff08;Program Database&#xff09;是一种用于存储调试信息的文件格式。它包含了源代码文件、符号表和其他调试相关的信息&#xff0c;可以帮助开发人员在调试过程中定位和解决问题 在调试中&#xff0c;PDB文件应该与编译生成的可执行文件&#xff08;如DLL或EX…

嵌入式仪器模块:DMM LCR SMU 及自动化测试软件

• 6 位数字表显示 • 24 位分辨率 • 250 KSPS 采样率 • 电源和数字 I/O 均采用隔离抗噪技术 应用场景 • 电压、电流、电阻、电感、电容的高精度测量 • 二极管/三极管测试 通道1222输入阻抗电压10 MΩHigh-Z, 10 MΩHigh-Z电流10 Ω50 mΩ / 2 Ω / 2 KΩ2 KΩ / 2 M…

如何理解external

external 函数应该只被外部函数调用但也可以被内部调用&#xff0c;但是这种内部调用也是有外部调用机制&#xff0c;即新产生message! 例子1 // SPDX-License-Identifier: GPL-3.0pragma solidity >0.8.2 <0.9.0;contract ExternalDemo{address public caller;functi…

高温应用中理想的油封材料选择

在现代工业生产中&#xff0c;油封是关键的密封元件&#xff0c;尤其在高温环境中&#xff0c;其材料选择直接关系到设备的可靠运行。本文将从多角度分析几种理想的高温油封材料及其应用场景。 氟橡胶(FKM)是目前高温油封材料的佼佼者。FKM因其卓越的耐高温性能(可耐受250C)和…