問題原因:
造成此類問題大致有兩個原因:
- PageHelper的不安全調用導致;
- supportMethodsArguments參數設置成了true,不明白的可以看下面的官方文檔說明;
- 此類問題皆可以參考官方文檔
大致內容爲:
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~