MyBaties分頁插件PageHelper的簡單使用

 

拋出問題:

若是想要將現有的select語句改成支持分頁功能的查詢語句該怎麼作呢?
最簡單的一種作法就是將全部的select語句都加上limit來實現分頁,這種作法有什麼問題呢?java

有沒有一種簡便方法實現呢?
Mybatis提供了plugin機制,容許咱們在Mybatis的原有處理流程上加入本身邏輯,全部咱們就可使用這種邏輯加上咱們的分頁邏輯,也就是實現攔截器。
Mybatis支持的攔截的接口有4個,Executor、ParameterHandler、ResultSetHandler、StatementHandler。關於分頁攔截器的配置和使用後期我會更新。
 mysql

1、PageHelper的介紹和使用

Mybatis的一個插件,PageHelper,很是方便mybatis分頁查詢。國內牛人的一個開源項目,有興趣的能夠去看源碼。在github上倉庫地址爲:Mybatis-PageHelper。它支持基本主流與經常使用的數據庫,這能夠在它的文檔上看到。這裏記錄一下使用的基本方法。PageHelpe開源地址:
github項目地址:https://github.com/pagehelper/Mybatis-PageHelper
碼雲 項目地址:http://git.oschina.net/free/Mybatis_PageHelpergit

 

2、項目配置

首先引入jar包依賴
<dependency>
    <groupId>com.github.pagehelper</groupId>
    <artifactId>pagehelper</artifactId>
    <version>4.1.4</version>
</dependency>

 

在mybatis的全局配置文件SqlMapConfig.xml中配置該插件
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <!-- 配置分頁插件 -->
    <plugins>
        <plugin interceptor="com.github.pagehelper.PageHelper">
            <!-- 設置數據庫類型 Oracle,Mysql,MariaDB,SQLite,Hsqldb,PostgreSQL六種數據庫-->        
            <property name="dialect" value="mysql"/>
        </plugin>
    </plugins>
</configuration>

 

3、基本使用

dao層:github

public List<User> queryUserListLikeName(@Param("name") String name);

mapper.xml:sql

<select id="queryUserListLikeName" parameterType="String" resultType="User">
    SELECT * FROM tb_user WHERE name LIKE '%${name}%'
</select>

service.java
 數據庫

public PageInfo<User> testQueryUserListLikeName() {
    //設置分頁條件,Parameters:pageNum 頁碼pageSize 每頁顯示數量count 是否進行count查詢
    PageHelper.startPage(1, 3, true);
    List<User> users = this.userMapper.queryUserListLikeName(null);
    //取分頁後結果
    PageInfo<User> pageInfo = new PageInfo<User>(users);
   
    //打印分頁信息
    System.out.println("數據總數:" + pageInfo.getTotal());
    System.out.println("數據總頁數:" + pageInfo.getPages());
    System.out.println("最後一頁:" + pageInfo.getLastPage());
    
    return pageInfo;
}

pageInfo.java安全

public class PageInfo<T> implements Serializable {
    private static final long serialVersionUID = 1L;
    //當前頁
    private int pageNum;
    //每頁的數量
    private int pageSize;
    //當前頁的數量
    private int size;
 
    //因爲startRow和endRow不經常使用,這裏說個具體的用法
    //能夠在頁面中"顯示startRow到endRow 共size條數據"
 
    //當前頁面第一個元素在數據庫中的行號
    private int startRow;
    //當前頁面最後一個元素在數據庫中的行號
    private int endRow;
    //總記錄數
    private long total;
    //總頁數
    private int pages;
    //結果集
    private List<T> list;
 
    //前一頁
    private int prePage;
    //下一頁
    private int nextPage;
 
    //是否爲第一頁
    private boolean isFirstPage = false;
    //是否爲最後一頁
    private boolean isLastPage = false;
    //是否有前一頁
    private boolean hasPreviousPage = false;
    //是否有下一頁
    private boolean hasNextPage = false;
    //導航頁碼數
    private int navigatePages;
    //全部導航頁號
    private int[] navigatepageNums;
    //導航條上的第一頁
    private int navigateFirstPage;
    //導航條上的最後一頁
    private int navigateLastPage;
 
    public PageInfo() {
    }
 
    /**
     * 包裝Page對象
     *
     * @param list
     */
    public PageInfo(List<T> list) {
        this(list, 8);
    }
 
    /**
     * 包裝Page對象
     *
     * @param list          page結果
     * @param navigatePages 頁碼數量
     */
    public PageInfo(List<T> list, int navigatePages) {
        if (list instanceof Page) {
            Page page = (Page) list;
            this.pageNum = page.getPageNum();
            this.pageSize = page.getPageSize();
 
            this.pages = page.getPages();
            this.list = page;
            this.size = page.size();
            this.total = page.getTotal();
            //因爲結果是>startRow的,因此實際的須要+1
            if (this.size == 0) {
                this.startRow = 0;
                this.endRow = 0;
            } else {
                this.startRow = page.getStartRow() + 1;
                //計算實際的endRow(最後一頁的時候特殊)
                this.endRow = this.startRow - 1 + this.size;
            }
        } else if (list instanceof Collection) {
            this.pageNum = 1;
            this.pageSize = list.size();
 
            this.pages = this.pageSize > 0 ? 1 : 0;
            this.list = list;
            this.size = list.size();
            this.total = list.size();
            this.startRow = 0;
            this.endRow = list.size() > 0 ? list.size() - 1 : 0;
        }
        if (list instanceof Collection) {
            this.navigatePages = navigatePages;
            //計算導航頁
            calcNavigatepageNums();
            //計算先後頁,第一頁,最後一頁
            calcPage();
            //判斷頁面邊界
            judgePageBoudary();
        }
    }
 
 
.......
}

注意:

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

以上就是PageHelper的基本使用,簡單方便的分頁插件。mybatis

相關文章
相關標籤/搜索