MyBaties分頁外掛PageHelper的簡單使用
阿新 • • 發佈:2018-12-10
丟擲問題:
如果想要將現有的select語句改為支援分頁功能的查詢語句該怎麼做呢?
最簡單的一種做法就是將所有的select語句都加上limit來實現分頁,這種做法有什麼問題呢?
有沒有一種簡便方法實現呢?
Mybatis提供了plugin機制,允許我們在Mybatis的原有處理流程上加入自己邏輯,所有我們就可以使用這種邏輯加上我們的分頁邏輯,也就是實現攔截器。
Mybatis支援的攔截的介面有4個,Executor、ParameterHandler、ResultSetHandler、StatementHandler。關於分頁攔截器的配置和使用後期我會更新。
一、PageHelper的介紹和使用
Mybatis的一個外掛,PageHelper,非常方便mybatis分頁查詢。國內牛人的一個開源專案,有興趣的可以去看原始碼。在github上倉庫地址為:Mybatis-PageHelper。它支援基本主流與常用的資料庫,這可以在它的文件上看到。這裡記錄一下使用的基本方法。PageHelpe開源地址:
github專案地址:https://github.com/pagehelper/Mybatis-PageHelper
碼雲 專案地址:http://git.oschina.net/free/Mybatis_PageHelper
二、專案配置
首先引入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>
三、基本使用
dao層:
public List<User> queryUserListLikeName(@Param("name") String name);
mapper.xml:
<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<>(list);
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的基本使用,簡單方便的分頁外掛。