得嘞,分頁外掛 PageHelper 返回記錄總數 total 竟然出錯了!

京东云开发者發表於2024-03-20

問題描述
分頁返回的記錄總數 total 和每頁數量 pageSize 一致,資料庫統計的數量大於當前返回的總記錄數 total,以下是相關程式碼

問題分析
sql 錯誤導致返回資訊有誤?
檢查結果:經過資料執行日誌中生成的 sql,sql 正常並且資料總條數也正確

PageHelper 使用方式錯誤,導致資料錯誤
檢查結果:透過與專案中其他地方使用記錄的對比,使用方式正確

返回結果後有中間處理導致總數減少
檢查結果:網上有人遇到 對返回結果有型別轉化導致 total 錯誤的情況, 以此類推,發現當前程式碼雖沒有對返回結果進行型別轉換但是對 mapper 返回的結果更換了例項物件然後將更換後的物件包裝,

進一步檢視包裝成 PageInfo時原始碼並沒有關於 total 引數的處理,

PageInfo構造方法

public class PageInfo extends PageSerializable {
/**

  • 包裝 Page 物件 *
  • @param list page 結果
  • @param navigatePages 頁碼數量
    */
    public PageInfo(List list, int navigatePages) {
    super(list);
    if (list instanceof Page) {
    Page page = (Page) list;
    this.pageNum = page.getPageNum();
    this.pageSize = page.getPageSize();

    this.pages = page.getPages();
    this.size = page.size();
    //由於結果是>startRow 的,所以實際的需要 +1
    if (this.size == 0) {
    this.startRow = 0;
    this.endRow = 0;
    } else {
    this.startRow = page.getStartRow() + 1;
    //計算實際的 endRow(最後一頁的時候特殊)
    this.endRow = this.startRow - 1 + this.size;
    }
    } else if (list instanceof Collection) {
    this.pageNum = 1;
    this.pageSize = list.size();

    this.pages = this.pageSize > 0 ? 1 : 0;
    this.size = list.size();
    this.startRow = 0;
    this.endRow = list.size() > 0 ? list.size() - 1 : 0;
    }
    if (list instanceof Collection) {
    this.navigatePages = navigatePages;
    //計算導航頁
    calcNavigatepageNums();
    //計算前後頁,第一頁,最後一頁
    calcPage();
    //判斷頁面邊界
    judgePageBoudary();
    }
    }
    }
    繼續檢視父類 PageSerializable,發現有關於 total 引數的處理,即 mapper 返回的 list 不是 Page 的例項時 total 會被設定為返回 list 的 size 大小

PageSerializable 構造方法

public PageSerializable(List list) {
this.list = list;
if(list instanceof Page){
this.total = ((Page) list).getTotal();
} else {
this.total = list.size();
}
}
進一步 debug,發現返回 list 確實不是 Page 類的例項,故推斷出這一結果是由於對 mapper 返回 list 結果更換了例項物件導致的,

再次確認 mapper 返回結果,是 Page 的例項

解決方案
使用 mapper 返回的物件直接構造 PageInfo 物件,並在此基礎上獲取分頁資訊

更正的程式碼如下:

最佳實踐
在使用 PageInfo pageInfo = new PageInfo<>(T); 構造 PageInfo 時直接使用 mapper 返回物件,不要進行型別轉換或轉存等操作,以免丟失資料。

相關文章