1. 程式人生 > 實用技巧 >pageHelper沒有正確分頁,sql拼接多加limit等引數。

pageHelper沒有正確分頁,sql拼接多加limit等引數。

pageHelper沒有正確分頁,sql拼接多加limit等引數。

背景:

日常敲程式碼,發現用了pageHelper真的方便,尤其是使用了pageInfo這個類,不用自己寫工具類了,直接將所有的頁碼資訊封裝到PageInfo裡,但是,使用過程中發生了sql語法錯誤,檢視之後發現sql語句又多加了limit或者在不應該排序的地方加了一個排序的規則。而且專案有的時候正常有的時候錯誤。

  1. 不分頁,查出多少條資料給出多少條:

    沒有分頁標誌。

  2. 多次重新整理頁面

出現這個,明明沒加limit,這個mapper也沒有分頁。

  1. 多次重新整理後查出來的資料也不正確了。庫裡明明有12條資料,結果查出來5條。

有時候正確有時候錯誤。

解決方案

檢視自己的寫語句,既然不分頁,先考慮是不是程式碼沒有寫對。

@GetMapping("/types/{id}")
public String types(Model model, @RequestParam(value = "page",required = false) Integer pageNum, @PathVariable Long id) {
    //找出所有的type
    List<TypeIndexDto> types = typeService.listType2Index();
    if (pageNum==null){
        pageNum=1;
    }
    if (id == -1) {
        id = types.get(0).getId();
    }
    //根據typeId查詢所屬部落格並羅列出來
    List<BlogIndexDto> blogIndexDtos = blogService.selectBlogByTypeId(id);
    PageHelper.startPage(pageNum,5);
    PageInfo<BlogIndexDto> pageInfo = new PageInfo<>(blogIndexDtos);
    model.addAttribute("types", types);
    model.addAttribute("page", pageInfo);
    model.addAttribute("activeType", id);
    return "types";
}

乍一看,其實沒有問題,但是讀到官網的這一條:

順序寫錯了。。。糾錯老長時間,修改下順序就行了。

當然,按照官網說的,使用PageHelper方法有可能產生執行緒安全問題,其實這就是因為pageHelper沒有跟在mybatis查詢方法之後導致的執行緒安全。具體可以檢視官網。

官網的解釋

PageHelper 方法使用了靜態的 ThreadLocal 引數,分頁引數和執行緒是繫結的。

只要你可以保證在 PageHelper 方法呼叫後緊跟 MyBatis 查詢方法,這就是安全的。因為 PageHelperfinally 程式碼段中自動清除了 ThreadLocal 儲存的物件。

如果程式碼在進入 Executor

前發生異常,就會導致執行緒不可用,這屬於人為的 Bug(例如介面方法和 XML 中的不匹配,導致找不到 MappedStatement 時), 這種情況由於執行緒不可用,也不會導致 ThreadLocal 引數被錯誤的使用。

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

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

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

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

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

這種寫法就能保證安全。

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

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

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

總結

在改錯的過程中,一度懷疑是pageHelper出了問題,想重寫分頁工具類,經過排錯後發現,根本不用,只要自己按照官網的來就可以避免不安全的呼叫pageHelper的方法。