SpringBoot整合Pagehelper分頁插件


在web開發中,數據的分頁是必不可少的。Pagehelper分頁插件很強大,雖說平時我們不需要用到它的很多功能,但是了解下還是有必要的。

官網:https://pagehelper.github.io/

注:在 MyBatis下使用。本節是在 SpringBoot整合mybatis 基礎上進行演示。

一、引入依賴

<!-- 核心啟動器, 包括auto-configuration、logging and YAML -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter</artifactId>
</dependency>
<!-- 數據庫操作需要的mysql 驅動包 -->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.1.48</version>
</dependency>
<!-- mybatis -->
<dependency>
    <groupId>org.mybatis.spring.boot</groupId>
    <artifactId>mybatis-spring-boot-starter</artifactId>
    <version>2.1.1</version>
</dependency>
<!-- pagehelper -->
<dependency>
    <groupId>com.github.pagehelper</groupId>
    <artifactId>pagehelper-spring-boot-starter</artifactId>
    <version>1.2.13</version>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
</dependency>

二、application.properties

#這里要注意&,可能在spring的xml中我們用的是轉義符號(&amp;),但是在這里不用
spring.datasource.url=jdbc:mysql://192.168.178.5:12345/mydb?characterEncoding=utf8&useUnicode=true&useSSL=false&serverTimezone=UTC
spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.type=com.zaxxer.hikari.HikariDataSource

####### mybatis #######
# 指定映射文件的具體位置
mybatis.mapper-locations=classpath:mapper/*.xml

####### pagehelper #######
# 默認情況下會使用 PageHelper 方式進行分頁,如果想要實現自己的分頁邏輯,
# 可以實現 Dialect(com.github.pagehelper.Dialect) 接口,然后配置該屬性為實現類的全限定名稱。
# 下面幾個參數都是針對默認 dialect 情況下的參數。使用自定義 dialect 實現時(不推薦),下面的參數沒有任何作用# 分頁的數據庫語言, oracle/mysql
pagehelper.helper-dialect=mysql
# 該參數對使用 RowBounds 作為分頁參數時有效。 當該參數設置為 true 時,
# 會將 RowBounds 中的 offset 參數當成 pageNum 使用,可以用頁碼和頁面大小兩個參數進行分頁。
pagehelper.offset-as-page-num= false
# 該參數對使用 RowBounds 作為分頁參數時有效。
# 當該參數設置為true時,使用 RowBounds 分頁會進行 count 查詢。
pagehelper.row-bounds-with-count=false
# 當該參數設置為 true 時,如果 pageSize=0 或者 RowBounds.limit = 0
# 就會查詢出全部的結果(相當於沒有執行分頁查詢,但是返回結果仍然是 Page 類型)。
pagehelper.page-size-zero=false
# 分頁合理化參數,默認值為false。當該參數設置為 true 時,pageNum<=0 時會查詢第一頁,
# pageNum>pages(超過總數時),會查詢最后一頁。默認false 時,直接根據參數進行查詢。
pagehelper.reasonable=true
# 為了支持startPage(Object params)方法,增加了該參數來配置參數映射,
# 用於從對象中根據屬性名取值, 可以配置 pageNum,pageSize,count,pageSizeZero,reasonable,
# 不配置映射的用默認值,
# 默認值為pageNum=pageNum;pageSize=pageSize;count=countSql;reasonable=reasonable;pageSizeZero=pageSizeZero。
pagehelper.params=pageNum=pageNum;pageSize=pageSize;count=countSql;reasonable=reasonable;pageSizeZero=pageSizeZero
# 支持通過 Mapper 接口參數來傳遞分頁參數,默認值false,分頁插件會從查詢方法的參數值中,
# 自動根據上面 params 配置的字段中取值,查找到合適的值時就會自動分頁。
pagehelper.support-methods-arguments=
# 當使用運行時動態數據源或沒有設置 helperDialect 屬性自動獲取數據庫類型時,
# 會自動獲取一個數據庫連接, 通過該屬性來設置是否關閉獲取的這個連接,默認true關閉,
# 設置為 false 后,不會關閉獲取的連接,這個參數的設置要根據自己選擇的數據源來決定。
pagehelper.close-conn=true
# 默認值為 false。設置為 true 時,允許在運行時根據多數據源自動識別對應方言的分頁
# (不支持自動選擇sqlserver2012,只能使用sqlserver)
pagehelper.auto-runtime-dialect=true

三、PageHelper.startPage 靜態方法調用

除了 PageHelper.startPage 方法外,還提供了類似用法的 PageHelper.offsetPage 方法。

在你需要進行分頁的 MyBatis 查詢方法前調用 PageHelper.startPage 靜態方法即可,緊跟在這個方法后的第一個MyBatis 查詢方法會被進行分頁。

public Page<Map<String,Object>> queryPage1(){
        //獲取第1頁,3條內容,默認查詢總數count
        PageHelper.startPage(1, 3);
        //緊跟着的第一個select方法會被分頁
        List<Map<String,Object>> list = userMapper.listUsers();
        // 分頁時,實際返回的結果list類型是Page<E>,如果想取出分頁信息,需要強制轉換為Page<E>
        // 也可以這樣 PageInfo<Map<String, Object>> pageInfo = new PageInfo<Map<String, Object>>(list);
        Page<Map<String, Object>> pageInfo = (Page<Map<String, Object>>)list;
        return pageInfo;
}

public Page<Map<String,Object>> queryPage2(Map<String,Object> params){
    //參數包含pageNum=1 和 pageSize=10 都可以直接這樣使用
    //支持 ServletRequest,Map,POJO 對象
    PageHelper.startPage(params);
    //緊跟着的第一個select方法會被分頁
    List<Map<String,Object>> list = userMapper.listUsers();
    Page<Map<String, Object>> pageInfo = (Page<Map<String, Object>>)list;

    //后面的不會被分頁,除非再次調用PageHelper.startPage
    List<Map<String,Object>> list2 = userMapper.listUsers();
    System.out.println("list2的大小是:" + list2.size());
    return pageInfo;
}

/**
 * 使用參數是安全的
 * 想要使用參數方式,需要配置 supportMethodsArguments 參數為 true,同時要配置 params 參數
 * 默認是pageSize和pageNum
 * 注:pageNum 和 pageSize 兩個屬性同時存在才會觸發分頁操作,在這個前提下,其他的分頁參數才會生效。
 */
public Page<Map<String,Object>> queryPage3(Map<String,Object> params){
    List<Map<String,Object>> list = userMapper.listUsers(params);
    Page<Map<String, Object>> pageInfo = (Page<Map<String, Object>>)list;
    return pageInfo;
}

/**
 * 使用 ISelect 接口調用是安全的
 * ISelect 接口方式除了可以保證安全外,還特別實現了將查詢轉換為單純的 count 查詢方式,
 * 這個方法可以將任意的查詢方法,變成一個 select count(*) 的查詢方法。
 *
 */
public PageInfo<Map<String,Object>> queryPage4(){
    //分頁,返回PageInfo分頁對象
    PageInfo<Map<String,Object>> pageInfo = PageHelper.startPage(1, 10).doSelectPageInfo(new ISelect() {
        @Override
        public void doSelect() {
            userMapper.listUsers();
        }
    });

    //count查詢,返回一個查詢語句的count數
    long total = PageHelper.count(new ISelect() {
        @Override
        public void doSelect() {
            userMapper.listUsers();
        }
    });
    System.out.println("總記錄數:" + total);
    return pageInfo;
}

四、什么時候會導致不安全的分頁

上面在講解的例子提到分頁安全,什么時候會導致不安全的分頁?

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>();
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM