解決PageHelper的上下文問(wèn)題導(dǎo)致SQL查詢結(jié)果不正確
前言
問(wèn)題的場(chǎng)景是偶爾出現(xiàn)某個(gè)查詢接口查詢出來(lái)的結(jié)果集不對(duì),現(xiàn)象都是清一色的缺少條數(shù),而且是偶發(fā)。
經(jīng)過(guò)代碼跟蹤和復(fù)現(xiàn),發(fā)現(xiàn)是PageHelper沒(méi)有正確使用導(dǎo)致的上下文問(wèn)題。
一、原因是什么
這個(gè)問(wèn)題的根源通常出現(xiàn)在 PageHelper 的分頁(yè)上下文沒(méi)有被正確清理,導(dǎo)致分頁(yè)上下文在沒(méi)有顯式調(diào)用 startPage 的情況下,影響了后續(xù)的查詢執(zhí)行。
二、可能原因及解決方案
1. PageHelper的上下文被意外繼承
在 PageHelper.startPage
調(diào)用之后,如果你有條件判斷導(dǎo)致某些 SQL 查詢沒(méi)有執(zhí)行,而其他查詢方法仍然執(zhí)行時(shí),分頁(yè)上下文可能會(huì)被錯(cuò)誤地傳遞到這些查詢中。
PageHelper
在后臺(tái)會(huì)通過(guò)線程局部變量(ThreadLocal
)來(lái)管理分頁(yè)信息,如果分頁(yè)上下文沒(méi)有被清理,后續(xù)的查詢可能會(huì)繼承之前的分頁(yè)設(shè)置。
解決方法:
使用 PageHelper.clearPage()
來(lái)手動(dòng)清理分頁(yè)上下文,確保分頁(yè)信息不會(huì)影響到后續(xù)查詢,尤其是條件判斷沒(méi)有執(zhí)行 SQL 時(shí),避免影響到后面的查詢。
// 調(diào)用分頁(yè) PageHelper.startPage(pageNum, pageSize); // 條件判斷 if (someCondition) { // 不執(zhí)行 SQL 查詢 } else { // 執(zhí)行 SQL 查詢 List<User> users = userMapper.selectUsers(); } // 清理分頁(yè)上下文,防止影響后續(xù)查詢 PageHelper.clearPage();
這樣,即使某些查詢因條件判斷未執(zhí)行,PageHelper.clearPage()
會(huì)清理分頁(yè)上下文,防止后續(xù)的查詢(無(wú)論是否分頁(yè))受到影響。
2. 查詢順序或上下文未清理
如果在多個(gè)查詢之間有分頁(yè)設(shè)置,但是在其中一些查詢沒(méi)有執(zhí)行時(shí),PageHelper.startPage()
仍然可能對(duì)后續(xù)查詢產(chǎn)生影響,導(dǎo)致它們不管是否顯式設(shè)置分頁(yè),都采用了分頁(yè)查詢的上下文。
解決方法:
- 確保每個(gè)分頁(yè)查詢后都調(diào)用
PageHelper.clearPage()
來(lái)清理分頁(yè)上下文。 - 確保每個(gè)查詢前都顯式調(diào)用
startPage
。
// 分頁(yè)查詢1 PageHelper.startPage(pageNum, pageSize); List<User> users = userMapper.selectUsers(); PageHelper.clearPage(); // 清理分頁(yè)上下文 // 分頁(yè)查詢2 PageHelper.startPage(nextPageNum, nextPageSize); List<Order> orders = orderMapper.selectOrders(); PageHelper.clearPage(); // 清理分頁(yè)上下文
3. 在多個(gè)方法之間使用分頁(yè)時(shí),未正確分離上下文
如果你在多個(gè)方法中使用了分頁(yè),并且沒(méi)有在分頁(yè)查詢之間清理上下文(clearPage
),分頁(yè)設(shè)置可能會(huì)相互干擾。
例如,如果方法 A 中沒(méi)有查詢數(shù)據(jù),而方法 B 中進(jìn)行了查詢,分頁(yè)信息可能會(huì)被繼承到方法 B。
解決方法:
確保每次分頁(yè)查詢之前,都顯式調(diào)用 startPage
,且每次分頁(yè)查詢后都清理分頁(yè)上下文。
// 方法A PageHelper.startPage(pageNum, pageSize); if (someCondition) { // 不執(zhí)行查詢 } else { // 執(zhí)行查詢 List<User> users = userMapper.selectUsers(); } PageHelper.clearPage(); // 清理分頁(yè)上下文 // 方法B PageHelper.startPage(nextPageNum, nextPageSize); List<Order> orders = orderMapper.selectOrders(); PageHelper.clearPage(); // 清理分頁(yè)上下文
4. 分頁(yè)設(shè)置影響其他查詢
由于 PageHelper
是基于線程局部變量(ThreadLocal
)來(lái)管理分頁(yè)上下文的,因此如果在方法之間傳遞分頁(yè)設(shè)置,但沒(méi)有清理,后續(xù)的查詢可能會(huì)錯(cuò)誤地繼承分頁(yè)設(shè)置,即使這些查詢本身不需要分頁(yè)。
解決方法:
- 確保在分頁(yè)查詢之后清理分頁(yè)上下文。
- 在查詢沒(méi)有設(shè)置分頁(yè)的情況下,確認(rèn)沒(méi)有隱式繼承分頁(yè)設(shè)置。
// 分頁(yè)查詢前顯式調(diào)用startPage PageHelper.startPage(pageNum, pageSize); List<User> users = userMapper.selectUsers(); // 清理分頁(yè)上下文 PageHelper.clearPage(); // 非分頁(yè)查詢 List<Order> orders = orderMapper.selectOrders(); // 這時(shí)應(yīng)該不再受分頁(yè)影響
總結(jié)
- 清理分頁(yè)上下文:每次分頁(yè)查詢結(jié)束后都調(diào)用
PageHelper.clearPage()
來(lái)清理分頁(yè)上下文,避免影響后續(xù)的查詢。 - 確保分頁(yè)設(shè)置生效:每次查詢前都要確保分頁(yè)設(shè)置已經(jīng)正確調(diào)用
startPage
。 - 避免條件判斷影響分頁(yè):如果條件判斷導(dǎo)致沒(méi)有執(zhí)行 SQL 查詢,確保分頁(yè)上下文被清理,避免對(duì)后續(xù)查詢產(chǎn)生影響。
通過(guò)這種方式,你可以確保分頁(yè)邏輯不會(huì)意外地影響到后續(xù)的查詢,即使某些查詢由于條件判斷而沒(méi)有執(zhí)行。
這些僅為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
Java爬蟲(chóng)實(shí)現(xiàn)爬取京東上的手機(jī)搜索頁(yè)面 HttpCliient+Jsoup
下面小編就為大家分享一篇Java爬蟲(chóng)實(shí)現(xiàn)爬取京東上的手機(jī)搜索頁(yè)面 HttpCliient+Jsoup,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2017-11-11Java中session存儲(chǔ)Users對(duì)象實(shí)現(xiàn)記住密碼
這篇文章主要介紹了Java中session存儲(chǔ)Users對(duì)象實(shí)現(xiàn)記住密碼,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-01-01Springboot RestTemplate 簡(jiǎn)單使用解析
這篇文章主要介紹了Springboot RestTemplate 簡(jiǎn)單使用解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-08-08解決執(zhí)行maven命令時(shí)提示Process terminated的問(wèn)題
這篇文章主要介紹了解決執(zhí)行maven命令時(shí)提示Process terminated的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-09-09詳細(xì)分析Java并發(fā)集合LinkedBlockingQueue的用法
這篇文章主要介紹了詳細(xì)分析Java并發(fā)集合LinkedBlockingQueue的用法,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-04-04Springboot整合freemarker 404問(wèn)題解決方案
這篇文章主要介紹了Springboot整合freemarker 404問(wèn)題解決方案,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-05-05Mybatis空值關(guān)聯(lián)的具體實(shí)現(xiàn)
在復(fù)雜的數(shù)據(jù)庫(kù)查詢中,處理空值關(guān)聯(lián)是一項(xiàng)常見(jiàn)的需求,本文就來(lái)介紹一下Mybatis空值關(guān)聯(lián)的具體實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2024-07-07Java多線程編程基石ThreadPoolExecutor示例詳解
這篇文章主要為大家介紹了Java多線程編程基石ThreadPoolExecutor示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-04-04