1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

        Mybatis plus 多租戶方案踩坑記錄

        共 4127字,需瀏覽 9分鐘

         ·

        2021-12-13 13:24

        Mybatis plus 多租戶方案踩坑記錄

        公司的老項目要改造多租戶,于是進入了大坑,本文寫點遇到的坑以及解決方案,每次遇到問題在網(wǎng)上搜了好久,記錄下來,防止以后忘掉。

        (一).方案

        網(wǎng)上有很多方案,本文只寫最后一種,即:表增加租戶id,實現(xiàn)數(shù)據(jù)隔離

        方案一:增加租戶id,在每一個mapper調(diào)用的地方,都手工加上租戶id

        例如:

        LambdaQueryWrapper lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(Entity::getTenantId,"tenantId");
        entityMapper.selectList(lambdaQueryWrapper);
        復(fù)制代碼

        這種方式復(fù)雜,工作量大,且容易漏。沒有采用

        方案二:使用mp官方的多租戶插件,此處代碼省略,自行去官方文檔上查詢

        (二).官方多租戶的方案的優(yōu)化和坑

        采用了官方文檔的多租戶插件后,前期調(diào)試很順利,crud 都自測過了,以為沒有問題了,于是就發(fā)測試環(huán)境了,但是隨著測試的深入,發(fā)現(xiàn)了好多問題和需要改動的地方,此處列舉:

        1.分析哪些需要加多租戶,哪些不需要加

        (1)租戶id的重寫 官方的默認(rèn)重寫方法是:

        @Override
        public Expression getTenantId() {
        return null;
        }
        復(fù)制代碼

        此處需要定義你的租戶id的獲取方法

        (2)租戶字段的定義

        private static final String TENANT_ID = "tenant_id";

        @Override
        public String getTenantIdColumn() {
        return TENANT_ID;
        }
        復(fù)制代碼

        (3)租戶攔截

        @Override
        public boolean ignoreTable(String tableName) {
        return TenantLineHandler.super.ignoreTable(tableName);
        }
        復(fù)制代碼

        此處我采用的方案是 表名攔截,代碼如下:

        @Override
        public boolean ignoreTable(String tableName) {

        /**
        * 此處的list,臨時用作攔截
        * 原因是:下面的表解析方法,用的是大駝峰轉(zhuǎn)下劃線,再跟sql攔截器攔截到的表名對比,如果匹配到了,則認(rèn)為該表需要多租戶拼接
        * 但是有的表沒有嚴(yán)格的按照大駝峰轉(zhuǎn)下劃線,所以這些表需要額外定義
        * @TableName 這個注解能否完成該職責(zé),目前還未測試,以后再說。
        */
        List 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);
        }
        復(fù)制代碼

        EntityUtils 方法代碼如下 (github上的一位小伙子寫的,侵權(quán)聯(lián)系我刪)

        /**
        * 判斷實體是否有某個屬性
        *
        * @param entityPath 實體全路徑
        * @param attrName 屬性名字
        * @return boolean
        */
        public static boolean isHaveAttr(String entityPath, String attrName) {
        Optional 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;
        }
        }
        復(fù)制代碼

        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ī)定版本




        com.github.jsqlparser
        jsqlparser
        2.0


        com.github.pagehelper
        pagehelper
        5.1.10



        復(fù)制代碼

        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)一下!)

        解決方法

        既然你失敗,那我就不用你好了,手動拼接,見下面忽略方法??

        4.忽略多租戶不生效

        我們都知道通過注解:@InterceptorIgnore(tenantLine = "on") 可以達(dá)到該mapper語句不進行sql解析,和不進行多租戶的改造。但是在實際應(yīng)用場景中發(fā)現(xiàn)有一個特殊的場景該注解不生效。

        例如:

        Page page = PageHelper.startPage(param.getPageNumber(), param.getPageSize());
        List experts = expertMapper.queryExpertList(page);
        復(fù)制代碼

        這個問題真的是浪費了我好久的時間,后來通過查閱資料,我發(fā)現(xiàn)@InterceptorIgnore在有分頁的時候,是會失效的,但是我又想,都是mp的東西,你自己都沖突,那怎么能行。

        然后我就發(fā)現(xiàn)PageHelper 這個東西,看著很奇怪。然后我就給去掉了,不進行分頁,果然可以了!注解生效了。完美,同時,mp都已經(jīng)提供了分頁的東西,為什么還要借助com.github的呢。

        然后改造如下:

        IPage page = new com.baomidou.mybatisplus.extension.plugins.pagination.Page<>(param.getPageNumber(),param.getPageSize())
        List experts = expertMapper.queryExpertList(expertMapping.dtoToEntity(param));


        作者:沒什么大不了zz
        鏈接:https://juejin.cn/post/7039605197877805063
        來源:稀土掘金
        著作權(quán)歸作者所有。商業(yè)轉(zhuǎn)載請聯(lián)系作者獲得授權(quán),非商業(yè)轉(zhuǎn)載請注明出處。



        瀏覽 174
        點贊
        評論
        收藏
        分享

        手機掃一掃分享

        分享
        舉報
        評論
        圖片
        表情
        推薦
        點贊
        評論
        收藏
        分享

        手機掃一掃分享

        分享
        舉報
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            91自啪区 | 一区二区三区A∨亂伦 | 国产欧美日韩视频在线 | 欧美一区二区三区四区夜夜大片 | 精品国偷自产在线视频 | 欧美老妇性生活第一页 | 女性性生活直播 | 爆操白虎穴 | 国产一区电影在线观看 | 91色情小说|