PageHelper 使用 ThreadLocal 的線程復(fù)用問(wèn)題,你用對(duì)了嗎?
點(diǎn)擊關(guān)注公眾號(hào),Java干貨及時(shí)送達(dá)??

前言
PageHelper 是較為常用的分頁(yè)插件,通過(guò)實(shí)現(xiàn) Mybatis 的 Interceptor 接口完成對(duì) query sql 的動(dòng)態(tài)分頁(yè),其中分頁(yè)參數(shù)由 ThreadLocal 進(jìn)行保存。
簡(jiǎn)單的 分頁(yè)執(zhí)行過(guò)程:
設(shè)置 page 參數(shù) 執(zhí)行 query 方法 Interceptor 接口 中校驗(yàn) ThreadLocal 中是否存在有設(shè)置的 page 參數(shù) 存在 page 參數(shù),重新生成? count sql?和?page sql,并執(zhí)行查詢。不存在 page 參數(shù),直接返回 查詢結(jié)果執(zhí)行? LOCAL_PAGE.remove()清除 page 參數(shù)
問(wèn)題場(chǎng)景
觀察上述的執(zhí)行過(guò)程,可以發(fā)現(xiàn),如果在第 1 步和第 2 步 之間發(fā)生異常,那么?LOCAL_PAGE?中當(dāng)前線程對(duì)應(yīng)的 page 參數(shù)并不會(huì) remove。
在不使用線程池的情況下,當(dāng)前線程在執(zhí)行完畢后會(huì)被銷(xiāo)毀,這時(shí) 當(dāng)前線程 中的 threadLocals 參數(shù) 將會(huì)被情況,也就清空 了?LOCAL_PAGE?中 當(dāng)前線程的 page 參數(shù)。
但是如果使用了線程池,當(dāng)前線程執(zhí)行完畢,并不會(huì)被銷(xiāo)毀,而是會(huì)將當(dāng)前線程再次存放到池中,標(biāo)記為空閑狀態(tài),以便后續(xù)使用。在后續(xù)使用這個(gè)線程的時(shí)候,由于 線程 的 threadLocals 依舊存在有值,盡管我們?cè)诘?1 步時(shí)未設(shè)置 page 參數(shù),第 3 步 的也能獲取到page參數(shù),從而生成?count sql?和?page sql,從而影響我們的正常查詢。
SpringBoot 項(xiàng)目中會(huì)使用內(nèi)置的 Tomcat 作為服務(wù)器,而Tomcat會(huì)默認(rèn)使用線程來(lái)處理請(qǐng)求,從而便引發(fā)了上述問(wèn)題。
解決方案
因?yàn)門(mén)omcat的線程是用來(lái)處理request請(qǐng)求,那么在請(qǐng)求完成時(shí),清空當(dāng)前線程的threadLocals 屬性值,也就是執(zhí)行?LOCAL_PAGE.remove()?即可。實(shí)現(xiàn)方式:
使用 aop,對(duì)所有 controller 進(jìn)行處理 實(shí)現(xiàn)? HandlerInterceptor?或者?WebRequestInterceptor?對(duì) request 請(qǐng)求的攔截器接口,通過(guò) afterCompletion 方法執(zhí)行?LOCAL_PAGE.remove()?!?推薦,實(shí)現(xiàn)方式簡(jiǎn)單
這里使用第二種方式,實(shí)現(xiàn)?HandlerInterceptor?接口:
public?class?PageLocalWebInterceptor?implements?HandlerInterceptor?{
????@Override
????public?void?afterCompletion(HttpServletRequest?request,?HttpServletResponse?response,?Object?handler,?Exception?ex)?throws?Exception?{
????????//?PageHelper.clearPage()?內(nèi)部調(diào)用?LOCAL_PAGE.remove()
????????PageHelper.clearPage();
????}
}
定義配置類(lèi),配置類(lèi)需實(shí)現(xiàn)?WebMvcConfigurer?接口完成對(duì)于WebMvc的相關(guān)配置 ,注冊(cè)?PageLocalWebInterceptor?:
@Configuration
public?class?FrameworkAutoConfig?implements?WebMvcConfigurer?{
????@Override
????public?void?addInterceptors(InterceptorRegistry?registry)?{
????????registry.addInterceptor(new?PageLocalWebInterceptor());
????}
}
來(lái)源:blog.csdn.net/qq_38245668/article/
details/105984171
最近面試BAT,整理一份面試資料《Java面試BATJ通關(guān)手冊(cè)》,覆蓋了Java核心技術(shù)、JVM、Java并發(fā)、SSM、微服務(wù)、數(shù)據(jù)庫(kù)、數(shù)據(jù)結(jié)構(gòu)等等。
獲取方式:點(diǎn)“在看”,關(guān)注公眾號(hào)并回復(fù)?Java?領(lǐng)取,更多內(nèi)容陸續(xù)奉上。
PS:因公眾號(hào)平臺(tái)更改了推送規(guī)則,如果不想錯(cuò)過(guò)內(nèi)容,記得讀完點(diǎn)一下“在看”,加個(gè)“星標(biāo)”,這樣每次新文章推送才會(huì)第一時(shí)間出現(xiàn)在你的訂閱列表里。
點(diǎn)“在看”支持小哈呀,謝謝啦??

