Mybatis?plus多租戶方案的實(shí)戰(zhàn)踩坑記錄
公司的老項(xiàng)目要改造多租戶,于是進(jìn)入了大坑,本文寫(xiě)點(diǎn)遇到的坑以及解決方案,每次遇到問(wèn)題在網(wǎng)上搜了好久,記錄下來(lái),防止以后忘掉。
(一).方案
網(wǎng)上有很多方案,本文只寫(xiě)最后一種,即:表增加租戶id,實(shí)現(xiàn)數(shù)據(jù)隔離
方案一:增加租戶id,在每一個(gè)mapper調(diào)用的地方,都手工加上租戶id
例如:
LambdaQueryWrapper<Entity> lambdaQueryWrapper = new LambdaQueryWrapper<>(); lambdaQueryWrapper.eq(Entity::getTenantId,"tenantId"); entityMapper.selectList(lambdaQueryWrapper);
這種方式復(fù)雜,工作量大,且容易漏。沒(méi)有采用
方案二:使用mp官方的多租戶插件,此處代碼省略,自行去官方文檔上查詢
(二).官方多租戶的方案的優(yōu)化和坑
采用了官方文檔的多租戶插件后,前期調(diào)試很順利,crud 都自測(cè)過(guò)了,以為沒(méi)有問(wèn)題了,于是就發(fā)測(cè)試環(huán)境了,但是隨著測(cè)試的深入,發(fā)現(xiàn)了好多問(wèn)題和需要改動(dòng)的地方,此處列舉:
1.分析哪些需要加多租戶,哪些不需要加
(1)租戶id的重寫(xiě)
官方的默認(rèn)重寫(xiě)方法是:
@Override
public Expression getTenantId() {
return null;
}
此處需要定義你的租戶id的獲取方法
(2)租戶字段的定義
private static final String TENANT_ID = "tenant_id";
@Override
public String getTenantIdColumn() {
return TENANT_ID;
}
(3)租戶攔截
@Override
public boolean ignoreTable(String tableName) {
return TenantLineHandler.super.ignoreTable(tableName);
}
此處我采用的方案是 表名攔截,代碼如下:
@Override
public boolean ignoreTable(String tableName) {
/**
* 此處的list,臨時(shí)用作攔截
* 原因是:下面的表解析方法,用的是大駝峰轉(zhuǎn)下劃線,再跟sql攔截器攔截到的表名對(duì)比,如果匹配到了,則認(rèn)為該表需要多租戶拼接
* 但是有的表沒(méi)有嚴(yán)格的按照大駝峰轉(zhuǎn)下劃線,所以這些表需要額外定義
* @TableName 這個(gè)注解能否完成該職責(zé),目前還未測(cè)試,以后再說(shuō)。
*/
List<String> list = new ArrayList<>();
list.add("das_standard_operation");
list.add("t_expert");
list.add("t_nominate_dict");
list.add("t_nominate_dict_history");
list.add("t_order");
list.add("t_standard_sort");
list.add("t_task");
list.add("t_task_confirm");
list.add("das_view");
if (list.contains(tableName)) {
return false;
}
EntityTableCache instance = EntityTableCache.getInstance();
if (null == instance || null == instance.getCacheData(tableName)) {
//如果未初始化到,不拼接租戶id
return true;
}
String entityPath = EntityTableCache.getInstance().getCacheData(tableName).toString();
//該方法會(huì)將大駝峰轉(zhuǎn)為下劃線,并完成初始化
return !EntityUtils.isHaveAttr(entityPath, COLUMN_TENANTID);
}
EntityUtils 方法代碼如下 (github上的一位小伙子寫(xiě)的,侵權(quán)聯(lián)系我刪)
/**
* 判斷實(shí)體是否有某個(gè)屬性
*
* @param entityPath 實(shí)體全路徑
* @param attrName 屬性名字
* @return boolean
*/
public static boolean isHaveAttr(String entityPath, String attrName) {
Optional<String> epOptional = Optional.ofNullable(entityPath);
if (!epOptional.isPresent()) {
return false;
}
try {
Class<?> aClass = Thread.currentThread().getContextClassLoader().loadClass(epOptional.get());
Field[] fields = aClass.getDeclaredFields();
for (Field field : fields) {
if (attrName.equals(field.getName())) {
return true;
}
}
return false;
} catch (ClassNotFoundException e) {
// log.error("SystemSqlParser->isHaveAttr類加載異常:" + e.getMessage());
return false;
}
}
2.jsqlparser 這個(gè)包與pagehelper 版本不對(duì)
在自測(cè)的時(shí)候,發(fā)現(xiàn)update語(yǔ)句攔不住,結(jié)果發(fā)現(xiàn)jsqlparser的版本號(hào)是1.2 而1.2與2.0(mp3.4.1 的jspparser版本是2.0),通過(guò)debug發(fā)現(xiàn),進(jìn)到了1.2的update方法
如圖:

1.2版本是getTables(),而2.0是如圖的getTable()
解決方法:
父pom強(qiáng)制規(guī)定版本
</dependencyManagement>
</dependencies>
<dependency>
<groupId>com.github.jsqlparser</groupId>
<artifactId>jsqlparser</artifactId>
<version>2.0</version>
</dependency>
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>5.1.10</version>
</dependency>
</dependencies>
</dependencyManagement>
3.sql解析失敗
1.regexp
目前發(fā)現(xiàn)使用到了regexp > 0 的sql 語(yǔ)句,解析器會(huì)報(bào)錯(cuò)
2.replace into 語(yǔ)句
這個(gè)語(yǔ)句目前我發(fā)現(xiàn)也是不支持的
上述的兩個(gè)問(wèn)題到現(xiàn)在還沒(méi)有解決,翻閱了一些資料,問(wèn)了一些同事,對(duì)這塊接觸的都比較少,目前mp最新版本使用的3.4.3.4中使用的com.github.jsqlparser:jsqlparser 是4.2版本,目前對(duì)上述的兩條仍然不支持(如果有哪位大神解決了,麻煩評(píng)論指導(dǎo)一下?。?/p>
解決方法
既然你失敗,那我就不用你好了,手動(dòng)拼接,見(jiàn)下面忽略方法??
4.忽略多租戶不生效
我們都知道通過(guò)注解:@InterceptorIgnore(tenantLine = "on") 可以達(dá)到該mapper語(yǔ)句不進(jìn)行sql解析,和不進(jìn)行多租戶的改造。但是在實(shí)際應(yīng)用場(chǎng)景中發(fā)現(xiàn)有一個(gè)特殊的場(chǎng)景該注解不生效。
例如:
Page<Expert> page = PageHelper.startPage(param.getPageNumber(), param.getPageSize()); List<Expert> experts = expertMapper.queryExpertList(page);
這個(gè)問(wèn)題真的是浪費(fèi)了我好久的時(shí)間,后來(lái)通過(guò)查閱資料,我發(fā)現(xiàn)@InterceptorIgnore在有分頁(yè)的時(shí)候,是會(huì)失效的,但是我又想,都是mp的東西,你自己都沖突,那怎么能行。
然后我就發(fā)現(xiàn)PageHelper 這個(gè)東西,看著很奇怪。然后我就給去掉了,不進(jìn)行分頁(yè),果然可以了!注解生效了。完美,同時(shí),mp都已經(jīng)提供了分頁(yè)的東西,為什么還要借助com.github的呢。
然后改造如下:
IPage<Expert> page = new com.baomidou.mybatisplus.extension.plugins.pagination.Page<>(param.getPageNumber(),param.getPageSize()) List<Expert> experts = expertMapper.queryExpertList(expertMapping.dtoToEntity(param));
總結(jié)
到此這篇關(guān)于Mybatis?plus多租戶方案實(shí)戰(zhàn)踩坑的文章就介紹到這了,更多相關(guān)Mybatis?plus多租戶方案內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
通過(guò)反射實(shí)現(xiàn)Java下的委托機(jī)制代碼詳解
這篇文章主要介紹了通過(guò)反射實(shí)現(xiàn)Java下的委托機(jī)制代碼詳解,具有一定借鑒價(jià)值,需要的朋友可以參考下。2017-12-12
SwiftUI中級(jí)List如何添加新內(nèi)容(2020年教程)
這篇文章主要介紹了SwiftUI中級(jí)List如何添加新內(nèi)容,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-01-01
JAVA幫助文檔全系列 JDK1.5 JDK1.6 JDK1.7 官方中英完整版整理
JDK(Java Development Kit,Java開(kāi)發(fā)包,Java開(kāi)發(fā)工具)是一個(gè)寫(xiě)Java的applet和應(yīng)用程序的程序開(kāi)發(fā)環(huán)境。它由一個(gè)處于操作系統(tǒng)層之上的運(yùn)行環(huán)境還有開(kāi)發(fā)者編譯,調(diào)試和運(yùn)行用Java語(yǔ)言寫(xiě)的applet和應(yīng)用程序所需的工具組成2014-01-01
詳解XML,Object,Json轉(zhuǎn)換與Xstream的使用
這篇文章主要介紹了詳解XML,Object,Json轉(zhuǎn)換與Xstream的使用的相關(guān)資料,需要的朋友可以參考下2017-02-02
Springboot+Redis執(zhí)行l(wèi)ua腳本的項(xiàng)目實(shí)踐
本文主要介紹了Springboot+Redis執(zhí)行l(wèi)ua腳本的項(xiàng)目實(shí)踐,詳細(xì)的介紹Redis與Lua腳本的結(jié)合應(yīng)用,具有一定的參考價(jià)值,感興趣的可以了解一下2023-09-09
mybatis中@Param注解總是報(bào)取不到參數(shù)問(wèn)題及解決
這篇文章主要介紹了mybatis中@Param注解總是報(bào)取不到參數(shù)問(wèn)題及解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-07-07
Maven遠(yuǎn)程倉(cāng)庫(kù)地址修改實(shí)現(xiàn)解析
這篇文章主要介紹了Maven遠(yuǎn)程倉(cāng)庫(kù)地址修改實(shí)現(xiàn)解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-11-11
在springboot中如何使用filter設(shè)置要排除的URL
這篇文章主要介紹了在springboot中如何使用filter設(shè)置要排除的URL,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-12-12

