MyBatis-Plus多租戶插件有時不生效問題

在使用MyBatis-Plus多租戶插件時遇到一個問題,同樣一個請求查詢,有時不會自動拼接租戶條件進行查詢,可能連續(xù)發(fā)送幾次有一次會是這樣,經(jīng)過對TenantLineInnerInterceptor類的調(diào)試跟蹤發(fā)現(xiàn)了問題所在。

一、問題跟蹤

問題就出現(xiàn)在這,在查詢之前會進入beforeQuery,在這里InterceptorIgnoreHelper.willIgnoreTenantLine(ms.getId())表示是否會忽略租戶條件,如果為true就表示不添加租戶條件。

20250227171817668.png

最終進入這個willIgnore函數(shù),如果ignoreStrategy不為空就會進入斷點部分代碼,導(dǎo)致返回為true,從而忽略多租戶條件。

20250227172134167.png

ignoreStrategy是由當(dāng)前線程變量IGNORE_STRATEGY_LOCAL中獲取得到,而設(shè)置這個變量的只有handle方法,所以是調(diào)用了handle方法導(dǎo)致。

20250227172319453.png

但實質(zhì)上IGNORE_STRATEGY_LOCAL是一個ThreadLocal對象,應(yīng)該只在當(dāng)前線程有效,而且我當(dāng)前查詢并沒有調(diào)用handle函數(shù),倒是有其它請求有調(diào)用這個方法,所以只有一種可能,線程污染導(dǎo)致。

至于兩個不同的請求為什么會線程污染,主要跟我項目依賴有關(guān),我使用的spring是采用tomcat作為web服務(wù)器,tomcat對請求的處理采用的是線程池的方式,而不是每個請求都建立一個線程,所以如果在A請求中調(diào)用了handle方法,但又沒清理,它就會一直留在線程當(dāng)中,當(dāng)下次某一個請求B進入,tomcat剛好將那個線程分配給這個請求就會出現(xiàn)這種情況。

二、解決方法

解決方法就是在調(diào)用handle函數(shù)后記得調(diào)用clearIgnoreStrategy進行清理。

InterceptorIgnoreHelper.handle(IgnoreStrategy.builder().tenantLine(true).build());  
try {  
    // 業(yè)務(wù)處理  
} catch (Exception e) {  
    // 清理線程  
    InterceptorIgnoreHelper.clearIgnoreStrategy();  
}

三、問題聯(lián)想

我這里使用的是spring boot3,默認(rèn)引入的就是tomcat6,采用的請求線程池是nio形式,在平常的業(yè)務(wù)中難免會使用ThreadLocal進行業(yè)務(wù)處理,最好在全局進行清理以防萬一:

/**  
 * 全局ThreadLocal清理過濾器  
 * @author 劉靖  
 */  
public class ThreadLocalCleanupFilter implements Filter {  
    @Override  
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {  
        try {  
            // 繼續(xù)執(zhí)行請求  
            chain.doFilter(request, response);  
        } finally {  
            // 清理 ThreadLocal 內(nèi)容  
            cleanupThreadLocal();  
        }  
    }  
  
    /**  
     * 清理 ThreadLocal 中的內(nèi)容  
     */  
    private void cleanupThreadLocal() {  
        // 這里清除所有 ThreadLocal 中的內(nèi)容  
        TenantThreadLocal.clear();  
        PermissionThreadLocal.cleanPermission();  
        DataScopeThreadLocal.clean();  
    }  
  
}

但由于tomcat6使用的請求線程池是nio,所以如果在一個請求處理過程中有文件之類的io阻塞操作,線程也可能會切換,所以如果一個請求中既有數(shù)據(jù)庫操作或者是依賴ThreadLocal的操作,盡量把io阻塞的操作放到最后。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容