SaaS多租戶,如何設(shè)計(jì)不铆?

一蝌焚、SaaS多租戶簡介

多租戶技術(shù)是一種軟件架構(gòu)技術(shù),它是在探討與實(shí)現(xiàn)如何于多用戶的環(huán)境下共用相同的系統(tǒng)或程序組件誓斥,并且仍可確保各用戶間數(shù)據(jù)的隔離性只洒。它是為共用的數(shù)據(jù)中心內(nèi)如何以單一系統(tǒng)架構(gòu)與服務(wù)提供多數(shù)客戶端相同甚至可定制化的服務(wù),并且仍可保障客戶的數(shù)據(jù)隔離劳坑。簡單來說是一個(gè)單獨(dú)的實(shí)例可以為多個(gè)組織服務(wù)毕谴。

多租戶是SaaS(Software-as-a-Service)下的一個(gè)概念,意思為軟件及服務(wù),即通過網(wǎng)絡(luò)提供軟件服務(wù)涝开。SaaS平臺供應(yīng)商將應(yīng)用軟件統(tǒng)一部署在自己的服務(wù)器上循帐,客戶端可以根據(jù)工作的實(shí)際需求,通過互聯(lián)網(wǎng)向廠商租用所需的應(yīng)用軟件服務(wù)舀武,按定購的服務(wù)多少和時(shí)間長短向廠商支付費(fèi)用惧浴,并通過互聯(lián)網(wǎng)獲得SaaS平臺供應(yīng)商提供的服務(wù)。

SaaS服務(wù)尤其利于一些中小企業(yè)奕剃,以低成本實(shí)現(xiàn)自己的軟件需求衷旅。


SaaS模式

什么是多租戶技術(shù)

多租戶技術(shù)或稱多重租賃技術(shù),是一種軟件架構(gòu)技術(shù)纵朋,是實(shí)現(xiàn)如何在多用戶環(huán)境下(此處的多用戶一般是面向企業(yè))共用相同的系統(tǒng)或程序組件柿顶,并且確保各用戶間數(shù)據(jù)隔離性。

在一臺服務(wù)器上運(yùn)行單個(gè)應(yīng)用實(shí)例操软,它為多個(gè)租戶(客戶)提供服務(wù)嘁锯。從定義中我們可以理解:多租戶是一種架構(gòu),目的是為了讓多用戶環(huán)境下使用同一套程序聂薪,且保證用戶間數(shù)據(jù)隔離家乘。多租戶的重點(diǎn)就是同程序下實(shí)現(xiàn)多用戶數(shù)據(jù)的隔離。

1.1什么是SaaS多租戶

SaaS藏澳,是Software-as-a-Service的縮寫名稱仁锯,意思為軟件即服務(wù),即通過網(wǎng)絡(luò)提供軟件服務(wù)翔悠。

SaaS平臺供應(yīng)商將應(yīng)用軟件統(tǒng)一部署在自己的服務(wù)器上业崖,客戶可以根據(jù)工作實(shí)際需求,通過互聯(lián)網(wǎng)向廠商訂購所需的應(yīng)用軟件服務(wù)蓄愁,按定購的服務(wù)多少和時(shí)間長短向廠商支付費(fèi)用双炕,并通過互聯(lián)網(wǎng)獲得SaaS平臺供應(yīng)商提供的服務(wù)。

SaaS服務(wù)通炒樽ィ基于一套標(biāo)準(zhǔn)軟件系統(tǒng)為成百上千的不同客戶(又稱為租戶)提供服務(wù)妇斤。這要求SaaS服務(wù)能夠支持不同租戶之間數(shù)據(jù)和配置的隔離,從而保證每個(gè)租戶數(shù)據(jù)的安全與隱私丹拯,以及用戶對諸如界面站超、業(yè)務(wù)邏輯、數(shù)據(jù)結(jié)構(gòu)等的個(gè)性化需求咽笼。由于SaaS同時(shí)支持多個(gè)租戶顷编,每個(gè)租戶又有很多用戶戚炫,這對支撐軟件的基礎(chǔ)設(shè)施平臺的性能剑刑、穩(wěn)定性和擴(kuò)展性提出很大挑戰(zhàn)。

多租戶是SaaS領(lǐng)域的特有產(chǎn)物,探究何為多租戶需回歸到對SaaS的理解上施掏。

SaaS服務(wù)是指部署在云上的钮惠,客戶可以按需購買,并通過網(wǎng)絡(luò)請求就能獲取到的服務(wù)七芭;也就是說素挽,在這樣的場景下,會有N個(gè)客戶同時(shí)使用同一套SaaS服務(wù)狸驳。

那么對SaaS服務(wù)供應(yīng)商來說预明,構(gòu)建SaaS體系需要完成兩部分工作:上層服務(wù)+底層多租戶系統(tǒng)。

上層服務(wù)是供應(yīng)商對外售賣的軟件服務(wù)耙箍,其可以為客戶創(chuàng)造價(jià)值撰糠、為公司帶來營收;而底層多租戶系統(tǒng)則是SaaS模式實(shí)現(xiàn)的具體方式辩昆,公司在對外售賣SaaS服務(wù)時(shí)阅酪,需要考慮如何實(shí)現(xiàn)客戶之間的數(shù)據(jù)隔離、服務(wù)的權(quán)限控制汁针、計(jì)費(fèi)管理等术辐;因此需要引入多租戶概念來解決上述問題。

通過多租戶系統(tǒng)施无,公司可以更好的管理客戶和上層服務(wù)辉词,客戶也可以更好的使用軟件服務(wù)。這也就是多租戶系統(tǒng)存在的意義了猾骡。

1.2 SaaS多租戶的優(yōu)勢

開發(fā)和運(yùn)維成本低

按需付費(fèi)较屿,節(jié)約成本

即租即用,軟件版本更新快

故障排查更及時(shí)

大數(shù)據(jù)和AI的能力支持更強(qiáng)大

1.3 多租戶模型


多租戶模型

如圖所示卓练,涉及主要模型有以下幾類:

(1)租戶:指一個(gè)企業(yè)客戶或是個(gè)人客戶隘蝎,租戶之間數(shù)據(jù)與行為隔離,上下級租戶間通過授權(quán)實(shí)現(xiàn)數(shù)據(jù)共享襟企。每個(gè)租戶只能操作歸屬或授權(quán)給該租戶的數(shù)據(jù)嘱么;

(2)組織:如果租戶是一個(gè)企業(yè)客戶,通常就會擁有自己的組織架構(gòu)顽悼;

(3)用戶:租戶下的具體使用者曼振,擁有用戶名、密碼蔚龙、郵箱等賬號信息的自然人冰评;

(4)角色:用戶操作權(quán)限的集合;

(5)員工:組織內(nèi)的某位員工木羹;

(6)解決方案:為了解決客戶的某類型業(yè)務(wù)問題甲雅,SaaS供應(yīng)商一般都將產(chǎn)品和服務(wù)組合在一起解孙,為客戶提供整體的打包方案;

(7)產(chǎn)品能力:能夠幫助客戶實(shí)現(xiàn)場景解決方案閉環(huán)的能力抛人;

(8)資源域:用來運(yùn)行1個(gè)或多個(gè)產(chǎn)品應(yīng)用的一套云資源環(huán)境弛姜;

(9)云資源:SaaS產(chǎn)品一般都部署在各種云平臺上,例如阿里云妖枚、騰訊云廷臼、華為云等。對這些云平臺提供的計(jì)算绝页、存儲荠商、網(wǎng)絡(luò)、容器等資源续誉,抽象為云資源结啼。

二、SaaS多租戶的數(shù)據(jù)隔離設(shè)計(jì)方案

多租戶對于用戶來說屈芜,最主要的一點(diǎn)就在于數(shù)據(jù)隔離郊愧。

絕對不能出現(xiàn):一個(gè)用戶登了A用戶單位的號,但是看到了B用戶單位的數(shù)據(jù)井佑。因此属铁,多租戶的數(shù)據(jù)庫設(shè)計(jì)方案和代碼實(shí)現(xiàn)就相當(dāng)有必要考慮了。

目前開發(fā)者們普遍接受的SaaS多租戶設(shè)計(jì)方案躬翁,常見的大概就3種:即為每個(gè)租戶提供獨(dú)立的數(shù)據(jù)庫焦蘑、獨(dú)立的表空間、按字段區(qū)分租戶盒发,每種方案都有其各自的適用情況例嘱。

一個(gè)租戶獨(dú)立一個(gè)數(shù)據(jù)庫

一個(gè)租戶獨(dú)立使用一個(gè)數(shù)據(jù)庫,那就意味著我們的SaaS系統(tǒng)需要連接多個(gè)數(shù)據(jù)庫宁舰,這種實(shí)現(xiàn)方案其實(shí)就和分庫分表架構(gòu)設(shè)計(jì)是一樣的拼卵,好處就是數(shù)據(jù)隔離級別特別高、安全性好蛮艰,畢竟一個(gè)租戶單用一個(gè)數(shù)據(jù)庫腋腮,但是物理硬件成本,維護(hù)成本也變高了壤蚜。

獨(dú)立的表空間

這種方案的實(shí)現(xiàn)方式即寡,就是所有租戶共用一個(gè)數(shù)據(jù)庫系統(tǒng),但是每個(gè)租戶在數(shù)據(jù)庫系統(tǒng)中擁有一個(gè)獨(dú)立的表空間袜刷。

按租戶id字段隔離租戶

這種方案是多租戶方案中最簡單的數(shù)據(jù)隔離方案聪富,即在每張表中都添加一個(gè)用于區(qū)分租戶的字段(如tenant_id或org_id啥的)來標(biāo)識每條數(shù)據(jù)屬于哪個(gè)租戶,當(dāng)進(jìn)行查詢的時(shí)候每條語句都要添加該字段作為過濾條件著蟹,其特點(diǎn)是所有租戶的數(shù)據(jù)全都存放在同一個(gè)表中墩蔓,數(shù)據(jù)的隔離性是最低的梢莽,完全是通過字段來區(qū)分的,很容易把數(shù)據(jù)搞串或者誤操作钢拧。

2.1三種數(shù)據(jù)隔離架構(gòu)設(shè)計(jì)的對比


隔離架構(gòu)設(shè)計(jì)對比

大部分公司都是采用第三種多租戶設(shè)計(jì)方案:按租戶id字段隔離租戶架構(gòu)設(shè)計(jì)實(shí)現(xiàn)多租戶數(shù)據(jù)隔離的。

因?yàn)檫@種方案服務(wù)器成本最低炕横,但是提高了開發(fā)成本源内。

2.2MyBatis-Plus多租戶插件優(yōu)雅實(shí)現(xiàn)數(shù)據(jù)隔離

該系統(tǒng)只有一個(gè)數(shù)據(jù)庫,所有租戶共用數(shù)據(jù)表份殿。

在每一個(gè)數(shù)據(jù)表中增加一列租戶ID膜钓,用以區(qū)分租戶的數(shù)據(jù)。

增刪改查時(shí)卿嘲,一定要帶上租戶ID颂斜,否則就會操作到其他租戶的數(shù)據(jù)。因此拾枣,這里的設(shè)計(jì)一定要重點(diǎn)考慮沃疮。

我們要保證的就是一定不要忘記帶上租戶ID。一個(gè)很好的方案就是通過AOP的方案梅肤,隱式的為我們的每一個(gè)SQL帶上這個(gè)租戶ID司蔬。

推薦使用MyBatis-Plus來操作數(shù)據(jù)庫的。它提供了插件的機(jī)制姨蝴,我們可以通過攔截它提供的四大組件的某些對象俊啼,某些方法,來操作SQL左医,動態(tài)的為我們的SQL拼接上租戶ID字段授帕。

當(dāng)然,MyBatis-Plus高版本提供了更加方便的攔截器浮梢,并且已經(jīng)將多租戶插件放入JAR包跛十,我們只需稍加實(shí)現(xiàn),并將該插件加入到MyBatis的攔截器鏈中秕硝,就可以不用再顯示的拼接租戶ID字段了偶器,降低了出錯(cuò)的概率。


三缝裤、MyBatisPlus實(shí)現(xiàn)多租戶功能

如果希望以最少的服務(wù)器為最多的租戶提供服務(wù)屏轰,并且租戶接受以犧牲隔離級別換取降低成本”锓桑可以采用方案三霎苗,即共享數(shù)據(jù)庫,共享數(shù)據(jù)架構(gòu)榛做,因?yàn)檫@種方案服務(wù)器成本最低唁盏,但是提高了開發(fā)成本内狸。

所以MyBatisPlus就提供了一種多租戶的解決方案,實(shí)現(xiàn)方式是基于多租戶插件TenantLinelnnerlnterceptor進(jìn)行實(shí)現(xiàn)的厘擂。

在MyBatis Plus中昆淡,采用“共享數(shù)據(jù)庫,共享數(shù)據(jù)架構(gòu)”方式實(shí)現(xiàn)多租戶刽严。

mybatisPlus提供了租戶處理器(Tenantld行級)昂灵,租戶之間共享數(shù)據(jù)庫,共享數(shù)據(jù)架構(gòu)舞萄,通過表字段(租戶ID)進(jìn)行數(shù)據(jù)邏輯隔離眨补。

該種實(shí)現(xiàn)方式,需要我們在要實(shí)現(xiàn)多租戶的表中添加tenant_id(租戶ID)字段倒脓,每次在對數(shù)據(jù)庫操作時(shí)都需要在where后面添加租戶判斷條件“tenant_id=用戶的租戶ID”撑螺。

然而,使用了MyBatis Plus后崎弃,我們就不需要每次都手動在where后面添加tenant_id條件甘晤。

注意事項(xiàng):

多租戶!=權(quán)限過濾饲做,不要亂用安皱,租戶之間時(shí)完全隔離的!Mа住酌伊!

啟用多租戶后所有執(zhí)行的method的sql都會進(jìn)行處理。

自寫的sql請按規(guī)范書寫(sql涉及到多個(gè)表的每個(gè)表都要給別名缀踪,特別是inner join的要寫標(biāo)準(zhǔn)的inner join)

<!-- Mybatis-Plus 增強(qiáng)CRUD -->

<dependency>

? ? <groupId>com.baomidou</groupId>

? ? <artifactId>mybatis-plus-boot-starter</artifactId>

? ? <version>3.5.1</version>

</dependency>

<!-- Mybatis-Plus 擴(kuò)展插件 -->

<dependency>

? ? <groupId>com.baomidou</groupId>

? ? <artifactId>mybatis-plus-extension</artifactId>

? ? <version>3.5.1</version>

</dependency>

TenantLineInnerInterceptor是MybatisPlus中提供的多租戶插件居砖,其使用方法大致分為下面4步:

3.1表及實(shí)體類添加租戶ID

應(yīng)用添加維護(hù)一張tenant(租戶表),記錄租戶的信息驴娃,每一個(gè)租戶奏候,有一個(gè)租戶ID。

然后唇敞,在需要進(jìn)行隔離的數(shù)據(jù)表上新增租戶id蔗草,例如,現(xiàn)在有數(shù)據(jù)庫表(user)如下:

租戶ID一般用tenant_id


將tenantId用來隔離租戶與租戶之間的數(shù)據(jù)疆柔,如果要查詢當(dāng)前服務(wù)商的用戶咒精,SQL大致如下:

SELECT * FROM table t WHERE t.tenantId = 1;

3.2application文件中添加多租戶配置和新增配置屬性類

(1)設(shè)置環(huán)境變量,配置攔截規(guī)則:

tenant.enable: 可以設(shè)置是否開啟多租戶旷档,

tenant.ignoreTables:需要進(jìn)行租戶id過濾的表名集合模叙。

tenant.filterTables:對多租戶的表設(shè)置白名單忽略多租戶攔截等。例如sys_user表結(jié)構(gòu)中鞋屈,沒有tenant_id多租戶字段范咨,那么多租戶攔截器不攔截該表故觅。

#多租戶配置

tenant:

? enable: true

? column: tenant_id

? filterTables:

? ignoreTables:

? ? - sys_app

? ? - sys_config

? ? - sys_dict_data

? ? - sys_dict_type

? ? - sys_logininfor

? ? - sys_menu

? ? - sys_notice

? ? - sys_oper_log

? ? - sys_role

? ? - sys_role_menu

? ? - sys_user

? ? - sys_user_role

? ignoreLoginNames:

(2)多租戶配置屬性類

import lombok.Data;

import org.springframework.boot.context.properties.ConfigurationProperties;

import org.springframework.stereotype.Component;

import java.util.List;

/**

* 多租戶配置屬性類

*

* @author hege

* @Date 2023-08-25

*

*/

@Data

@ConfigurationProperties(prefix = "tenant")

public class TenantProperties {

? ? /**

? ? * 是否開啟多租戶

? ? */

? ? private Boolean enable = true;

? ? /**

? ? * 租戶id字段名

? ? */

? ? private String column = "tenant_id";

? ? /**

? ? * 需要進(jìn)行租戶id過濾的表名集合

? ? */

? ? private List<String> filterTables;

? ? /**

? ? * 需要忽略的多租戶的表,此配置優(yōu)先filterTables渠啊,若此配置為空输吏,則啟用filterTables

? ? */

? ? private List<String> ignoreTables;

? ? /**

? ? * 需要排除租戶過濾的登錄用戶名

? ? */

? ? private List<String> ignoreLoginNames;

}

3.3編寫多租戶處理器實(shí)現(xiàn)TenantLineHandler接口

在 MyBatis Plus 中,提供了 TenantLineInnerInterceptor 插件和 TenantLineHandler 接口替蛉。

其中:

TenantLineInnerInterceptor 插件用來自動向每個(gè) SQL 的 where 后面添加判斷條件“tenant_id=用戶的租戶ID”贯溅。

而 TenantLineHandler 接口用來給 TenantLineInnerInterceptor 插件提供租戶ID、租戶字段名灭返。

TenantLineHandler 接口定義如下:

public interface TenantHandler {

? /**

? * 獲取租戶 ID 值表達(dá)式盗迟,支持多個(gè) ID 條件查詢

? * 支持自定義表達(dá)式坤邪,比如:tenant_id in (1,2) @since 2019-8-2

? * @param where 參數(shù) true 表示為 where 條件 false 表示為 insert 或者 select 條件

? * @return 租戶 ID 值表達(dá)式

? */

? Expression getTenantId(boolean where);

? /**

? * 獲取租戶字段名

? * @return 租戶字段名

? */

? String getTenantIdColumn();

? /**

? * 根據(jù)表名判斷是否進(jìn)行過濾

? * @param tableName 表名

? * @return 是否進(jìn)行過濾, true:表示忽略熙含,false:需要解析多租戶字段

? */

? boolean doTableFilter(String tableName);

}

實(shí)現(xiàn)TenantHandler接口并實(shí)現(xiàn)它的方法,下面是一個(gè)例子:

import com.baomidou.mybatisplus.extension.plugins.handler.TenantLineHandler;

import net.sf.jsqlparser.expression.Expression;

import net.sf.jsqlparser.expression.LongValue;

import net.sf.jsqlparser.expression.NullValue;

import org.springframework.security.core.Authentication;

import org.springframework.security.core.context.SecurityContext;

import org.springframework.security.core.context.SecurityContextHolder;

import java.util.List;

/**

* 多租戶處理器實(shí)現(xiàn)TenantLineHandler接口

*

* @author hege

* @Date 2023-08-25

*/

public class MultiTenantHandler implements TenantLineHandler {

? ? private final TenantProperties properties;

? ? public MultiTenantHandler(TenantProperties properties) {

? ? ? ? this.properties = properties;

? ? }

? ? /**

? ? * 獲取租戶ID值表達(dá)式艇纺,只支持單個(gè)ID值 (實(shí)際應(yīng)該從用戶信息中獲取)

? ? *

? ? * @return 租戶ID值表達(dá)式

? ? */

? ? @Override

? ? public Expression getTenantId() {

? ? ? ? //實(shí)際應(yīng)該從用戶信息中獲取

? ? ? ? if(SecurityUtils.getTenantLoginUser()!=null)

? ? ? ? {

? ? ? ? ? ? //SecurityUtils 從ThreadLocal里面的安全上下文 中獲取 用戶所歸屬的單位id(租戶id)

? ? ? ? ? ? Long tenantId = SecurityUtils.getLoginUser().getUser().getRootPartyId();

? ? ? ? ? ? if(tenantId!=null)

? ? ? ? ? ? {

? ? ? ? ? ? ? ? return new LongValue(tenantId);

? ? ? ? ? ? }

? ? ? ? }

? ? ? ? return new LongValue(0);

? ? }

? ? /**

? ? * 獲取租戶字段名,默認(rèn)字段名叫: tenant_id

? ? *

? ? * @return 租戶字段名

? ? */

? ? @Override

? ? public String getTenantIdColumn() {


? ? ? ? //通過配置獲取

? ? ? ? return properties.getColumn();

? ? }

? ? /**

? ? * 根據(jù)表名判斷是否忽略拼接多租戶條件

? ? *

? ? * 默認(rèn)都要進(jìn)行解析并拼接多租戶條件

? ? *

? ? * @param tableName 表名

? ? * @return 是否忽略, true:表示忽略怎静,false:需要解析并拼接多租戶條件

? ? */

? ? @Override

? ? public boolean ignoreTable(String tableName) {

? ? ? ? //忽略指定用戶對租戶的數(shù)據(jù)過濾

? ? ? ? List<String> ignoreLoginNames=properties.getIgnoreLoginNames();


? ? ? ? //SecurityUtils 從ThreadLocal里面的安全上下文 中獲取 用戶名稱

? ? ? ? String loginName=SecurityUtils.getTenantUsername();

? ? ? ? if(null!=ignoreLoginNames && ignoreLoginNames.contains(loginName)){

? ? ? ? ? ? return true;

? ? ? ? }

? ? ? ? //忽略指定表對租戶數(shù)據(jù)的過濾

? ? ? ? List<String> ignoreTables = properties.getIgnoreTables();

? ? ? ? if (null != ignoreTables && ignoreTables.contains(tableName)) {

? ? ? ? ? ? return true;

? ? ? ? }

? ? ? ? return false;

? ? }

}

SecurityUtils 從ThreadLocal里面的安全上下文 中獲取 用戶名稱, 用戶所歸屬的單位id(租戶id)

3.4MybatisPlus配置類啟用多租戶攔截插件運(yùn)行sql實(shí)例:

前面講到黔衡,在 MyBatis Plus 中蚓聘,提供了 TenantLineInnerInterceptor 插件和 TenantLineHandler 接口。

其中盟劫,TenantLineInnerInterceptor 插件用來自動向每個(gè) SQL 的 where 后面添加判斷條件“tenant_id=用戶的租戶ID”夜牡。

TenantLineInnerInterceptor 插件 調(diào)用 TenantLineHandler 接口用來給 提供租戶ID、租戶字段名侣签。

使用 @Configuration 和 @Bean 注解配置 MyBatis Plus 的多租戶插件塘装,

iimport 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.OptimisticLockerInnerInterceptor;

import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;

import com.baomidou.mybatisplus.extension.plugins.inner.TenantLineInnerInterceptor;

import org.springframework.boot.context.properties.EnableConfigurationProperties;

import org.springframework.context.annotation.Bean;

import org.springframework.context.annotation.Configuration;

import org.springframework.transaction.annotation.EnableTransactionManagement;

/**

* Mybatis Plus 配置

*

* @author hege

*/

@EnableTransactionManagement(proxyTargetClass = true)

@Configuration

@EnableConfigurationProperties(TenantProperties.class)

public class MybatisPlusConfig {

? ? /**

? ? * 如果用了分頁插件注意先 add TenantLineInnerInterceptor 再 add PaginationInnerInterceptor

? ? *

? ? * @param tenantProperties

? ? * @return

? ? */

? ? @Bean

? ? public MybatisPlusInterceptor mybatisPlusInterceptor(TenantProperties tenantProperties) {

? ? ? ? MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();

? ? ? ? if (Boolean.TRUE.equals(tenantProperties.getEnable())) {

? ? ? ? ? ? // 啟用多租戶插件攔截

? ? ? ? ? ? interceptor.addInnerInterceptor(new TenantLineInnerInterceptor(new MultiTenantHandler(tenantProperties)));

? ? ? ? }

? ? ? ? // 分頁插件

? ? ? ? interceptor.addInnerInterceptor(paginationInnerInterceptor());

? ? ? ? // 樂觀鎖插件

? ? ? ? interceptor.addInnerInterceptor(optimisticLockerInnerInterceptor());

? ? ? ? // 阻斷插件

? ? ? ? interceptor.addInnerInterceptor(blockAttackInnerInterceptor());

? ? ? ? return interceptor;

? ? }

}

配置好之后,不管是查詢影所、新增蹦肴、修改刪除方法,MP都會自動加上租戶ID的標(biāo)識猴娩,測試如下:

@Test

public void select(){

? List<User> users = userMapper.selectList(Wrappers.<User>lambdaQuery().eq(User::getAge, 18));

? users.forEach(System.out::println);

}

運(yùn)行sql實(shí)例:

DEBUG==> Preparing: SELECT id, login_name, name, password,

? ? ? email, salt, sex, age, phone, user_type, status,

? ? organization_id, create_time, update_time, version,

? ? tenant_id FROM sys_user

? WHERE sys_user.tenant_id = '001' AND is_delete = '0' AND age = ?

驗(yàn)證結(jié)果:

針對MybatisPlus提供的API阴幌、自定義Mapper中的statement均可正常攔截,會在SQL執(zhí)行增刪改查的時(shí)候自動加上tenant_id卷中。

3.5特定SQL語句忽略攔截

如果在程序中矛双,有部分SQL不需要加上租戶ID的表示,需要過濾特定的sql蟆豫,或者對于一些超級管理員使用的接口背零,希望跨租戶查詢、免數(shù)據(jù)鑒權(quán)時(shí)无埃,無需多租戶攔截徙瓶。

怎么辦毛雇?

可以通過下面幾種方式實(shí)現(xiàn)忽略攔截:

方法1:使用MybatisPlus框架自帶的@InterceptorIgnore注解,以用在Mapper類上侦镇,也可以用在方法上

方法2:添加超級用戶賬號白名單灵疮,在自定義的Handler里進(jìn)行邏輯判斷,跳過攔截

方法3:添加數(shù)據(jù)表白名單壳繁,在自定義的Handler里進(jìn)行邏輯判斷震捣,跳過攔截

使用MybatisPlus框架自帶的@InterceptorIgnore注解,以用在Mapper類上闹炉,也可以用在方法上蒿赢, 下面是一個(gè)例子:

/**

* 使用@InterceptorIgnore注解,忽略多租戶攔截 <br/>

* 注解@InterceptorIgnore可以用在Mapper類上渣触,也可以用在方法上

*

* @param id

* @return

*/

@InterceptorIgnore(tenantLine = "true")

UserOrgVO myFindByIdNoTenant(@Param(value = "id") Long id);

參考文獻(xiàn)

https://mp.weixin.qq.com/s/TR75wnxsXgFZ2ot1dOvX2w

https://mp.weixin.qq.com/s/CVTuEINWHCLue1oB7Yr3ng

https://mp.weixin.qq.com/s/Nl5Oll9GcF6JB8JvIb2YqA

https://zhuanlan.zhihu.com/p/420696556

https://blog.csdn.net/CSDN2497242041/article/details/132525117

原文鏈接:https://blog.csdn.net/qq_45038038/article/details/135575700

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末羡棵,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子嗅钻,更是在濱河造成了極大的恐慌皂冰,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,817評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件养篓,死亡現(xiàn)場離奇詭異秃流,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)柳弄,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,329評論 3 385
  • 文/潘曉璐 我一進(jìn)店門舶胀,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人碧注,你說我怎么就攤上這事嚣伐。” “怎么了应闯?”我有些...
    開封第一講書人閱讀 157,354評論 0 348
  • 文/不壞的土叔 我叫張陵纤控,是天一觀的道長。 經(jīng)常有香客問我碉纺,道長船万,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,498評論 1 284
  • 正文 為了忘掉前任骨田,我火速辦了婚禮耿导,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘态贤。我一直安慰自己舱呻,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,600評論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著箱吕,像睡著了一般芥驳。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上茬高,一...
    開封第一講書人閱讀 49,829評論 1 290
  • 那天兆旬,我揣著相機(jī)與錄音,去河邊找鬼怎栽。 笑死丽猬,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的熏瞄。 我是一名探鬼主播脚祟,決...
    沈念sama閱讀 38,979評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼强饮!你這毒婦竟也來了由桌?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,722評論 0 266
  • 序言:老撾萬榮一對情侶失蹤胡陪,失蹤者是張志新(化名)和其女友劉穎沥寥,沒想到半個(gè)月后碍舍,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體柠座,經(jīng)...
    沈念sama閱讀 44,189評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,519評論 2 327
  • 正文 我和宋清朗相戀三年片橡,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了妈经。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,654評論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡捧书,死狀恐怖吹泡,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情经瓷,我是刑警寧澤爆哑,帶...
    沈念sama閱讀 34,329評論 4 330
  • 正文 年R本政府宣布,位于F島的核電站舆吮,受9級特大地震影響揭朝,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜色冀,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,940評論 3 313
  • 文/蒙蒙 一潭袱、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧锋恬,春花似錦屯换、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,762評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽嘉抓。三九已至,卻和暖如春晕窑,著一層夾襖步出監(jiān)牢的瞬間掌眠,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,993評論 1 266
  • 我被黑心中介騙來泰國打工幕屹, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留蓝丙,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,382評論 2 360
  • 正文 我出身青樓望拖,卻偏偏與公主長得像渺尘,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子说敏,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,543評論 2 349

推薦閱讀更多精彩內(nèi)容