Mybatis?plus多租戶方案的實戰(zhàn)踩坑記錄
公司的老項目要改造多租戶,于是進入了大坑,本文寫點遇到的坑以及解決方案,每次遇到問題在網(wǎng)上搜了好久,記錄下來,防止以后忘掉。
(一).方案
網(wǎng)上有很多方案,本文只寫最后一種,即:表增加租戶id,實現(xiàn)數(shù)據(jù)隔離
方案一:增加租戶id,在每一個mapper調(diào)用的地方,都手工加上租戶id
例如:
LambdaQueryWrapper<Entity> lambdaQueryWrapper = new LambdaQueryWrapper<>(); lambdaQueryWrapper.eq(Entity::getTenantId,"tenantId"); entityMapper.selectList(lambdaQueryWrapper);
這種方式復(fù)雜,工作量大,且容易漏。沒有采用
方案二:使用mp官方的多租戶插件,此處代碼省略,自行去官方文檔上查詢
(二).官方多租戶的方案的優(yōu)化和坑
采用了官方文檔的多租戶插件后,前期調(diào)試很順利,crud 都自測過了,以為沒有問題了,于是就發(fā)測試環(huán)境了,但是隨著測試的深入,發(fā)現(xiàn)了好多問題和需要改動的地方,此處列舉:
1.分析哪些需要加多租戶,哪些不需要加
(1)租戶id的重寫
官方的默認重寫方法是:
@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,臨時用作攔截 * 原因是:下面的表解析方法,用的是大駝峰轉(zhuǎn)下劃線,再跟sql攔截器攔截到的表名對比,如果匹配到了,則認為該表需要多租戶拼接 * 但是有的表沒有嚴格的按照大駝峰轉(zhuǎn)下劃線,所以這些表需要額外定義 * @TableName 這個注解能否完成該職責,目前還未測試,以后再說。 */ 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(); //該方法會將大駝峰轉(zhuǎn)為下劃線,并完成初始化 return !EntityUtils.isHaveAttr(entityPath, COLUMN_TENANTID); }
EntityUtils 方法代碼如下 (github上的一位小伙子寫的,侵權(quán)聯(lián)系我刪)
/** * 判斷實體是否有某個屬性 * * @param entityPath 實體全路徑 * @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 這個包與pagehelper 版本不對
在自測的時候,發(fā)現(xiàn)update語句攔不住,結(jié)果發(fā)現(xiàn)jsqlparser的版本號是1.2 而1.2與2.0(mp3.4.1 的jspparser版本是2.0),通過debug發(fā)現(xiàn),進到了1.2的update方法
如圖:
1.2版本是getTables(),而2.0是如圖的getTable()
解決方法:
父pom強制規(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 語句,解析器會報錯
2.replace into 語句
這個語句目前我發(fā)現(xiàn)也是不支持的
上述的兩個問題到現(xiàn)在還沒有解決,翻閱了一些資料,問了一些同事,對這塊接觸的都比較少,目前mp最新版本使用的3.4.3.4中使用的com.github.jsqlparser:jsqlparser 是4.2版本,目前對上述的兩條仍然不支持(如果有哪位大神解決了,麻煩評論指導(dǎo)一下?。?/p>
解決方法
既然你失敗,那我就不用你好了,手動拼接,見下面忽略方法??
4.忽略多租戶不生效
我們都知道通過注解:@InterceptorIgnore(tenantLine = "on") 可以達到該mapper語句不進行sql解析,和不進行多租戶的改造。但是在實際應(yīng)用場景中發(fā)現(xiàn)有一個特殊的場景該注解不生效。
例如:
Page<Expert> page = PageHelper.startPage(param.getPageNumber(), param.getPageSize()); List<Expert> experts = expertMapper.queryExpertList(page);
這個問題真的是浪費了我好久的時間,后來通過查閱資料,我發(fā)現(xiàn)@InterceptorIgnore在有分頁的時候,是會失效的,但是我又想,都是mp的東西,你自己都沖突,那怎么能行。
然后我就發(fā)現(xiàn)PageHelper 這個東西,看著很奇怪。然后我就給去掉了,不進行分頁,果然可以了!注解生效了。完美,同時,mp都已經(jīng)提供了分頁的東西,為什么還要借助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多租戶方案實戰(zhàn)踩坑的文章就介紹到這了,更多相關(guān)Mybatis?plus多租戶方案內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Springboot使用Junit測試沒有插入數(shù)據(jù)的原因
這篇文章主要介紹了Springboot使用Junit測試沒有插入數(shù)據(jù)的原因,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-04-04mybatis-plus插入一條數(shù)據(jù),獲取插入數(shù)據(jù)自動生成的主鍵問題
這篇文章主要介紹了mybatis-plus插入一條數(shù)據(jù),獲取插入數(shù)據(jù)自動生成的主鍵問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2023-12-12打開.properties中文顯示unicode編碼問題以及解決
這篇文章主要介紹了打開.properties中文顯示unicode編碼問題以及解決方案,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2024-01-01java 使用poi 導(dǎo)入Excel數(shù)據(jù)到數(shù)據(jù)庫的步驟
這篇文章主要介紹了java 使用poi 導(dǎo)入Excel 數(shù)據(jù)到數(shù)據(jù)庫的步驟,幫助大家更好的理解和使用Java,感興趣的朋友可以了解下2020-12-12