成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

原來PageHelper還有這個坑!

數據庫 其他數據庫
PageHelper是Mybatis-Plus中的一個插件,主要用于實現數據庫的分頁查詢功能。其核心原理是將傳入的頁碼和條數賦值給一個Page對象,并保存到本地線程ThreadLocal中。

哈嘍,大家好,我是了不起。

Mybatis插件PageHelper很多人都會使用吧,有一次Copy的時候忘了去掉PageHelper.startPaeg()方法,結果導致數據查不到,debug 的時候發現第一次查詢沒有數據,再查詢一次就有數據了,這個坑竟然也花了一點時間,那么今天就把這個坑填平。

這里我們一起看看其原理以及日常使用注意事項。

如何使用PageHelper

PageHelper是Mybatis-Plus中的一個插件,主要用于實現數據庫的分頁查詢功能。其核心原理是將傳入的頁碼和條數賦值給一個Page對象,并保存到本地線程ThreadLocal中。接下來,PageHelper會進入Mybatis的攔截器環節,在攔截器中獲取并處理剛才保存在ThreadLocal中的分頁參數。這些分頁參數會與原本的SQL語句和內部已經定義好的SQL進行拼接,從而完成帶有分頁處理的SQL語句的構建。

Pagehelper 有很多種使用方式,下面列出官方給出的幾種使用方式。

//第一種,RowBounds方式的調用
    List<Country> list = sqlSession.selectList("x.y.selectIf", null, new RowBounds(0, 10));

    //第二種,Mapper接口方式的調用,推薦這種使用方式。
    PageHelper.startPage(1, 10);
    List<Country> list = countryMapper.selectIf(1);

    //第三種,Mapper接口方式的調用,推薦這種使用方式。
    PageHelper.offsetPage(1, 10);
    List<Country> list = countryMapper.selectIf(1);

    //第四種,參數方法調用
    //存在以下 Mapper 接口方法,你不需要在 xml 處理后兩個參數
    public interface CountryMapper {
        List<Country> selectByPageNumSize(
                @Param("user") User user,
                @Param("pageNum") int pageNum,
                @Param("pageSize") int pageSize);
    }
    //配置supportMethodsArguments=true
    //在代碼中直接調用:
    List<Country> list = countryMapper.selectByPageNumSize(user, 1, 10);

    //第五種,參數對象
    //如果 pageNum 和 pageSize 存在于 User 對象中,只要參數有值,也會被分頁
    //有如下 User 對象
    public class User {
        //其他fields
        //下面兩個參數名和 params 配置的名字一致
        private Integer pageNum;
        private Integer pageSize;
    }
    //存在以下 Mapper 接口方法,你不需要在 xml 處理后兩個參數
    public interface CountryMapper {
        List<Country> selectByPageNumSize(User user);
    }
    //當 user 中的 pageNum!= null && pageSize!= null 時,會自動分頁
    List<Country> list = countryMapper.selectByPageNumSize(user);

    //第六種,ISelect 接口方式
    //jdk6,7用法,創建接口
    Page<Country> page = PageHelper.startPage(1, 10).doSelectPage(new ISelect() {
        @Override
        public void doSelect() {
            countryMapper.selectGroupBy();
        }
    });
    //jdk8 lambda用法
    Page<Country> page = PageHelper.startPage(1, 10).doSelectPage(()-> countryMapper.selectGroupBy());

    //也可以直接返回PageInfo,注意doSelectPageInfo方法和doSelectPage
    pageInfo = PageHelper.startPage(1, 10).doSelectPageInfo(new ISelect() {
        @Override
        public void doSelect() {
            countryMapper.selectGroupBy();
        }
    });
    //對應的lambda用法
    pageInfo = PageHelper.startPage(1, 10).doSelectPageInfo(() -> countryMapper.selectGroupBy());

    //count查詢,返回一個查詢語句的count數
    long total = PageHelper.count(new ISelect() {
        @Override
        public void doSelect() {
            countryMapper.selectLike(country);
        }
    });
    //lambda
    total = PageHelper.count(()->countryMapper.selectLike(country));

PageHelper原理

其核心原理是將傳入的頁碼和條數賦值給一個Page對象,并保存到本地線程ThreadLocal中。

下面以常見的使用方式看一下:

PageHelper.startPage(1, 10, orderBy);

經過一些列的循環俄羅斯套娃調用之后,來到了這里:

public static <E> Page<E> startPage(int pageNum, int pageSize, boolean count, Boolean reasonable, Boolean pageSizeZero) {
        Page<E> page = new Page<E>(pageNum, pageSize, count);
        page.setReasonable(reasonable);
        page.setPageSizeZero(pageSizeZero);
        //當已經執行過orderBy的時候
        Page<E> oldPage = getLocalPage();
        if (oldPage != null && oldPage.isOrderByOnly()) {
            page.setOrderBy(oldPage.getOrderBy());
        }
        setLocalPage(page);
        return page;
    }
  1. 重點在setLocalPage(page) 這個方法,將page對象放到了靜態變量ThreadLocal中。

圖片圖片

  1. 查詢接口進來的時候, PageHelper中的Threadlocal對象中就保存的該線程對應的分頁參數,在調用查詢的時候就會拿出來使用。

PageHelper 中有寫了一個 com.github.pagehelper.PageInterceptor , 這里是執行分頁的地方。如果你想要寫其他的攔截器,也可以自定義一個mybatis plugin包攔截器,在這里對sql進行處理。

圖片圖片

  1. 在PageInterceptor  中有一個主要interceptor方法,在方法中需要判斷是否需要分頁,如果需要分頁,則獲取分頁信息,查詢數據量等。

圖片圖片

  1. 接下來,PageHelper會進入Mybatis的攔截器環節,在攔截器中獲取并處理剛才保存在ThreadLocal中的分頁參數。這些分頁參數會與原本的SQL語句和內部已經定義好的SQL進行拼接,從而完成帶有分頁處理的SQL語句的構建。需要注意一點的是在finally中remove掉 ThreadLocal對象中當前線程的page對象。

圖片圖片

  1. 調用skip方法, 并獲取分頁參數 判斷是否需要分頁。

圖片圖片

  1. 從靜態ThreadLocal中獲取page對象,

圖片圖片

PageHelper在執行這一過程時,會判斷SQL的類型,只有當該SQL是查詢操作時,才會進入分頁邏輯。并且,在進入分頁邏輯處理后,PageHelper會通過反射獲取該方法的參數,判斷是否存在IPage對象(這是Mybatis-Plus中的另一個分頁對象)的實現類。如果存在這樣的實現類,那么也會進行相應的分頁處理。

PageHelper注意事項

使用PageHelper分頁推薦使用  PageHelper.startPage(1, 10)  這種方式。

另外startPage語句最好緊挨著查詢語句,避免中間拋出異常,沒有辦法清除ThreadLocal中當前線程的page對象。

下面看一下官方給出的不安全的用法 和推薦的例子:

不安全用法:下面的方法如果不走查詢的話,page對象就會保留在當前線程中,算是一個內存泄漏,如果下一個mybatis查詢方法剛好是這個線程的時候,就會被動分頁。

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

推薦用法,主要是緊挨著mybatis查詢方法,查詢結束后,page對象就被清理,對線程后續的運行不受影響。

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

回到最開始的那個坑,原因就在于錯誤的使用了PageHelper.startPage(page,size), 這里的分頁參數只是調用下游系統的分頁參數,不應該再這里使用,所以在第一頁的時候是沒問題的,到第二頁的時候,查詢就出問題了,數據庫中沒有那么多數據,所以會查不到數據。 debug的時候,執行一次數據查詢操作,把page對象消耗掉了,第二次查詢的數據沒有分頁參數,所以就可以正常查詢出數據。

責任編輯:武曉燕 來源: Java技術指北
相關推薦

2022-03-21 08:55:53

RocketMQ客戶端過濾機制

2022-07-26 01:00:12

Eureka延遲注冊

2021-09-03 11:15:18

場景sql配置

2021-01-14 05:08:44

編譯鏈接

2017-07-04 14:01:40

機房機柜

2024-05-13 16:22:25

固態硬盤接口硬盤

2023-11-27 13:19:00

數據AI

2022-10-17 08:17:47

位掩碼Java變量

2025-04-08 08:12:26

Next.js組件ChatGPT

2024-10-06 13:41:25

2024-01-31 12:34:16

panic錯誤檢測recover

2018-01-31 16:12:47

筆記本輕薄本游戲本

2022-06-20 10:00:57

Python工具包代碼

2018-07-12 14:59:44

獵網

2021-08-10 13:50:32

內存電腦軟件

2023-05-31 07:57:12

筆記本電腦信譽度

2017-06-16 16:16:36

庫存扣減查詢

2018-09-13 10:59:30

Redis鍵值存儲

2023-05-07 23:22:24

golang

2018-06-26 15:00:24

Docker安全風險
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 国产日韩视频 | 一区二视频 | 欧美成人a∨高清免费观看 老司机午夜性大片 | 九九99九九精彩46 | 精品一二区 | 日日夜夜免费精品 | 欧美日韩在线精品 | av在线一区二区三区 | 欧美成人一区二区三区 | 日韩在线中文字幕 | 亚洲 欧美 日韩在线 | 亚洲首页| 欧美一区二区免费视频 | 国产区免费视频 | 看片91| 久久精品亚洲精品国产欧美 | 日本一区二区三区在线观看 | 黄色国产在线播放 | 色综合天天综合网国产成人网 | www国产成人免费观看视频,深夜成人网 | 日韩看片| 久久久国产一区二区三区四区小说 | 日本中文字幕日韩精品免费 | 中文字幕福利 | 久久99精品久久久久久国产越南 | 一区二区久久 | 欧美日韩国产在线 | 欧美日韩高清在线一区 | 国产日韩欧美一区二区 | 亚洲精品一二三区 | 99reav | 欧美视频免费 | 欧美中文字幕一区二区三区亚洲 | 五月免费视频 | 国产四区| 国产一区二区三区精品久久久 | 永久免费av | 国产一区二区三区欧美 | 91久久伊人 | 亚洲视频在线一区 | 少妇无套高潮一二三区 |