Mybatis分頁插件PageHelper5.x會把原自定義limit語句後面添加limit?的問題

問題原因:

造成此類問題大致有兩個原因:

  1. PageHelper的不安全調用導致;
  2. supportMethodsArguments參數設置成了true,不明白的可以看下面的官方文檔說明;
  3. 此類問題皆可以參考官方文檔

大致內容爲:

1). PageHelper 安全調用

  •  使用 RowBounds 和 PageRowBounds 參數方式是極其安全的
  •  使用參數方式是極其安全的
  •  使用 ISelect 接口調用是極其安全的

ISelect 接口方式除了可以保證安全外,還特別實現了將查詢轉換爲單純的 count 查詢方式,這個方法可以將任意的查詢方法,變成一個 select count(*) 的查詢方法。

2). 什麼時候會導致不安全的分頁?

PageHelper 方法使用了靜態的 ThreadLocal 參數,分頁參數和線程是綁定的。

只要你可以保證在 PageHelper 方法調用後緊跟 MyBatis 查詢方法,這就是安全的。因爲 PageHelper 在 finally 代碼段中自動清除了 ThreadLocal 存儲的對象。

如果代碼在進入 Executor 前發生異常,就會導致線程不可用,這屬於人爲的 Bug(例如接口方法和 XML 中的不匹配,導致找不到 MappedStatement 時), 這種情況由於線程不可用,也不會導致 ThreadLocal 參數被錯誤的使用。

但是如果你寫出下面這樣的代碼,就是不安全的用法:

PageHelper.startPage(1, 10);
List<Country> list;
if(param1 != null){
    list = countryMapper.selectIf(param1);
} else {
    list = new ArrayList<Country>();
}

這種情況下由於 param1 存在 null 的情況,就會導致 PageHelper 生產了一個分頁參數,但是沒有被消費,這個參數就會一直保留在這個線程上。當這個線程再次被使用時,就可能導致不該分頁的方法去消費這個分頁參數,這就產生了莫名其妙的分頁。

上面這個代碼,應該寫成下面這個樣子:

List<Country> list;
if(param1 != null){
    PageHelper.startPage(1, 10);
    list = countryMapper.selectIf(param1);
} else {
    list = new ArrayList<Country>();
}

這種寫法就能保證安全。

如果你對此不放心,你可以手動清理 ThreadLocal 存儲的分頁參數,可以像下面這樣使用:

List<Country> list;
if(param1 != null){
    PageHelper.startPage(1, 10);
    try{
        list = countryMapper.selectAll();
    } finally {
        PageHelper.clearPage();
    }
} else {
    list = new ArrayList<Country>();
}

這麼寫很不好看,而且沒有必要。

3). supportMethodsArguments:支持通過 Mapper 接口參數來傳遞分頁參數,默認值false,分頁插件會從查詢方法的參數值中,自動根據上面 params 配置的字段中取值,查找到合適的值時就會自動分頁。 使用方法可以參考測試代碼中的 com.github.pagehelper.test.basic 包下的 ArgumentsMapTest 和 ArgumentsObjTest

我的原因就是 參數設置成了true~

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章