大家好,我是大明哥,一個專注於【死磕 Java】系列創作的男人
個人網站:https://www.cmsblogs.com/。專注於 Java 優質系列文章分享,提供一站式 Java 學習資料
某天我正在工位上聽著 Vicotry,愉快地敲著 hello world ,這感覺就像我寫的程式碼能征服世界。突然運維給我打了一個電話,說我們某臺伺服器 OOM 了,要我過去看下,這感覺就像 xxx,你懂的。
去運維室、登入伺服器、檢視日誌、....一頓操作猛如虎,看到一個 List 物件 600MB +(原諒我們伺服器 low,運維比較小氣,就給 1C2G 的伺服器),檢查當時的 SQL 語句,一看,我的乖乖,將近 4000w + 條資料。我的第一感覺就是,難道又是哪個業務在匯出大批量資料?但是我們所有的 Excel 匯出資料都做了校驗,資料量大於 5w 條就後臺分批次匯出(所以有時候你要慶幸伺服器 low,因為伺服器 low,你就需要進行各種各樣的優化,所有大資料量的操作都需要想辦法優化,所以我們這個應用就有了各種有意思的騷操作,後面有機會分享下)。難道沒有控制住?看了日誌並沒有發現大資料量的 Excel 匯出,所以可以斷定是分頁的地方沒有分頁。看程式碼在一個 if
語句裡面找到了坑,如下:
PageHelper.startPage(queryDTO.getPage(), queryDTO.getLimit());
Page<UserDTO> page;
if (isWitchFlag()) {
page = userMapper.selectUserList(queryDTO);
}
isWitchFlag()
:
private boolean isWitchFlag() {
String witchFlag = systemConfigMapper.selectSwitchFlag("key");
return "1".equals(witchFlag);
}
對 PageHelper 不是很熟悉的人一定不知道這個坑在哪裡!在 PageHelper 使用文件(https://pagehelper.github.io/faq/)中第一句就闡述了:
只有緊跟在 PageHelper.startPage 方法後的第一個 Mybatis 的查詢(Select)方法會被分頁。。請注意關鍵詞緊跟。為什麼要緊跟呢?因為 PageHelper 的分頁原理使用了 ThreadLocal,他的分頁引數和執行緒是繫結在一起的,當我們執行 PageHelper.startPage()
語句時,他會將分頁引數繫結到 ThreadLocal 中:
setLocalPage()
:
在攔截器 PageInterceptor
中,最後的 finally 會將 Page 分頁資訊給 remove 掉:
所以,上面那段程式碼的分頁資訊被 if 語句中的 select 查詢語句給消耗掉了,下面真正需要分頁的語句當然就不會執行分頁資訊啦。怎麼解決?兩種方案:
- 治標不治本:將
PageHelper.startPage()
挪到 if 語句裡面,讓真正的查詢語句緊挨著它。這種方案不治本的原因在於,如果又有小夥伴不知道這個坑,有可能又會踩。 - 治標治本:使用 Function Lamdba 表示式。
使用 Function Lamdba 來將 PageHelper.startPage()
與分頁查詢語句緊挨在一起,規避掉這個坑
首先我們需要定義一個 PageHelperTool,該 PageHelperTool 是封裝了分頁語句:
@Builder
public class PageHelperTool<P,R> {
private final Function<P, Page<R>> pageFunction;
public Page<R> getPageInfo(P request) {
PageHelper.startPage(((PageRequest)request).getPage(),((PageRequest)request).getLimit());
return pageFunction.apply(request);
}
}
然後將分頁的地方全部替換為 PageHelperTool 就可以了:
Page<UserDTO> page;
if (isWitchFlag()) {
PageHelperTool<QueryDTO,UserDTO> pageHelperTool = PageHelperTool.<QueryDTO,UserDTO>builder()
.pageFunction(userMapper::selectUserList)
.build();
page = pageHelperTool.getPageInfo(queryDTO);
}
這樣就可以徹底解決因誤用 PageHelper 導致分頁失效的問題了。
最後一句話:注意看文件啊!!!!!!