1、POM依賴html
PageHelper的依賴以下。須要新的版本能夠去maven上自行選擇java
<!-- PageHelper 插件分頁 -->
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>4.0.1</version>
</dependency>mysql
2、Mybatis對PageHelper的配置git
打開Mybatis配置文件,通常在Resource路徑下mybatis-config.xml。github
<configuration>
<settings>
<!-- 設置啓用數據庫字段下劃線映射到java對象的駝峯式命名屬性,默認爲false -->
<setting name="mapUnderscoreToCamelCase" value="true" />
</settings>
<objectWrapperFactory type="com.maomao.xwz.mybatis.handle.MapWrapperFactory"/>
<plugins>
<!-- com.github.pagehelper爲PageHelper類所在包名 -->
<plugin interceptor="com.github.pagehelper.PageHelper">
<!-- 4.0.0之後版本能夠不設置該參數 -->
<property name="dialect" value="mysql"/>
<!-- 該參數默認爲false -->
<!-- 設置爲true時,會將RowBounds第一個參數offset當成pageNum頁碼使用 -->
<!-- 和startPage中的pageNum效果同樣-->
<property name="offsetAsPageNum" value="true"/>
<!-- 該參數默認爲false -->
<!-- 設置爲true時,使用RowBounds分頁會進行count查詢 -->
<property name="rowBoundsWithCount" value="true"/>
<!-- 設置爲true時,若是pageSize=0或者RowBounds.limit = 0就會查詢出所有的結果 -->
<!-- (至關於沒有執行分頁查詢,可是返回結果仍然是Page類型)-->
<property name="pageSizeZero" value="true"/>
<!-- 3.3.0版本可用 - 分頁參數合理化,默認false禁用 -->
<!-- 啓用合理化時,若是pageNum<1會查詢第一頁,若是pageNum>pages會查詢最後一頁 -->
<!-- 禁用合理化時,若是pageNum<1或pageNum>pages會返回空數據 -->
<property name="reasonable" value="false"/>
<!-- 3.5.0版本可用 - 爲了支持startPage(Object params)方法 -->
<!-- 增長了一個`params`參數來配置參數映射,用於從Map或ServletRequest中取值 -->
<!-- 能夠配置pageNum,pageSize,count,pageSizeZero,reasonable,orderBy,不配置映射的用默認值 -->
<!-- 不理解該含義的前提下,不要隨便複製該配置 -->
<property name="params" value="pageNum=start;pageSize=limit;"/>
<!-- 支持經過Mapper接口參數來傳遞分頁參數 -->
<property name="supportMethodsArguments" value="true"/>
<!-- always老是返回PageInfo類型,check檢查返回類型是否爲PageInfo,none返回Page -->
<property name="returnPageInfo" value="check"/>
</plugin>
</plugins>
</configuration>sql
3、PageHelper分頁使用數據庫
1)只統計查詢總數量count緩存
public PageInfo selectByExample() {
PageHelper.startPage(1, -1);
List list = this.baseMapper.selectByExample(new BsFeedbackExample());
PageInfo pageInfo = new PageInfo(list);
log.info(JSONObject.toJSONString(pageInfo));
return pageInfo;
}安全
執行sql日誌:mybatis
2)正常分頁
public PageInfo selectByExample1() {
PageHelper.startPage(1, 1);
List list = this.baseMapper.selectByExample(new BsFeedbackExample());
PageInfo pageInfo = new PageInfo(list);
log.info(JSONObject.toJSONString(pageInfo));
return pageInfo;
}
執行sql日誌:
3)分頁統計總數
public PageInfo selectByExample2() {
PageHelper.startPage(1, 1, true);
List list = this.baseMapper.selectByExample(new BsFeedbackExample());
PageInfo pageInfo = new PageInfo(list);
log.info(JSONObject.toJSONString(pageInfo));
return pageInfo;
}
執行sql日誌:
4) 分頁不統計總數
public PageInfo selectByExample3() {
PageHelper.startPage(1, 1, false);
List list = this.baseMapper.selectByExample(new BsFeedbackExample());
PageInfo pageInfo = new PageInfo(list);
log.info(JSONObject.toJSONString(pageInfo));
return pageInfo;
}
執行sql日誌:
5) 查詢所有數據
public PageInfo selectByExample3() {
PageHelper.startPage(1, 0);
List list = this.baseMapper.selectByExample(new BsFeedbackExample());
PageInfo pageInfo = new PageInfo(list);
log.info(JSONObject.toJSONString(pageInfo));
return pageInfo;
}
執行sql日誌:
6) 分頁排序orderBy
public PageInfo selectByExample5() {
String orderBy = "id desc";
PageHelper.startPage(1, 2, orderBy);
List list = this.baseMapper.selectByExample(new BsFeedbackExample());
PageInfo pageInfo = new PageInfo(list);
log.info(JSONObject.toJSONString(pageInfo));
return pageInfo;
}
執行sql日誌:
7) 直接傳入分頁參數RowBounds
public PageInfo selectByExample6() {
List list = this.baseMapper.selectByExample(new BsFeedbackExample(), new RowBounds(2, 1));
PageInfo pageInfo = new PageInfo(list);
log.info(JSONObject.toJSONString(pageInfo));
return pageInfo;
}
執行sql日誌:
4、PageHelper如何確保安全性
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>();
}
一、 線程安全
PageHelper 方法使用了靜態的 ThreadLocal 參數,分頁參數和線程是綁定的。PageHelper.startPage方法調用後,將分頁參數設置在ThreadLocal中。
/**
* 基礎分頁方法
*
* @author liuzh
*/
public abstract class PageMethod {
protected static final ThreadLocal<Page> LOCAL_PAGE = new ThreadLocal<Page>();
protected static boolean DEFAULT_COUNT = true;
/**
* 開始分頁
*
* @param pageNum 頁碼
* @param pageSize 每頁顯示數量
* @param count 是否進行count查詢
* @param reasonable 分頁合理化,null時用默認配置
* @param pageSizeZero true且pageSize=0時返回所有結果,false時分頁,null時用默認配置
*/
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;
}
/**
* 開始分頁
*
* @param offset 頁碼
* @param limit 每頁顯示數量
*/
public static <E> Page<E> offsetPage(int offset, int limit) {
return offsetPage(offset, limit, DEFAULT_COUNT);
}
/**
* 開始分頁
*
* @param offset 頁碼
* @param limit 每頁顯示數量
* @param count 是否進行count查詢
*/
public static <E> Page<E> offsetPage(int offset, int limit, boolean count) {
Page<E> page = new Page<E>(new int[]{offset, limit}, count);
//當已經執行過orderBy的時候
Page<E> oldPage = getLocalPage();
if (oldPage != null && oldPage.isOrderByOnly()) {
page.setOrderBy(oldPage.getOrderBy());
}
setLocalPage(page);
return page;
}
/**
* 排序
*
* @param orderBy
*/
public static void orderBy(String orderBy) {
Page<?> page = getLocalPage();
if (page != null) {
page.setOrderBy(orderBy);
} else {
page = new Page();
page.setOrderBy(orderBy);
page.setOrderByOnly(true);
setLocalPage(page);
}
}
二、Mybatis分頁攔截
定義了Mybatis攔截器,在Mybatis執行sql前,進行攔截,針對sql進行分頁處理;
/**
* Mybatis - 通用分頁攔截器<br/>
* 項目地址 : http://git.oschina.net/free/Mybatis_PageHelper
*
* @author liuzh/abel533/isea533
* @version 5.0.0
*/
@SuppressWarnings({"rawtypes", "unchecked"})
@Intercepts(
{
@Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class}),
@Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class, CacheKey.class, BoundSql.class}),
}
)
public class PageInterceptor implements Interceptor {
//緩存count查詢的ms
protected Cache<String, MappedStatement> msCountMap = null;
private Dialect dialect;
private String default_dialect_class = "com.github.pagehelper.PageHelper";
private Field additionalParametersField;
private String countSuffix = "_COUNT";
@Override
public Object intercept(Invocation invocation) throws Throwable {
三、分頁參數內置查詢sql
MySqlDialect中加載AbstractHelperDialect實現,從線程中取出分頁參數,生成分頁sql;
常常提到的count查詢,實際上是PageHelper幫助咱們生成的一個MappedStatement內存對象,它能夠免去咱們在XXXMapper.xml內單獨聲明一個sql count查詢,咱們只須要寫一個sql分頁業務查詢便可。
/**
* 針對 PageHelper 的實現
*
* @author liuzh
* @since 2016-12-04 14:32
*/
public abstract class AbstractHelperDialect extends AbstractDialect implements Constant {
/**
* 獲取分頁參數
*
* @param <T>
* @return
*/
public <T> Page<T> getLocalPage() {
return PageHelper.getLocalPage();
}
1、明確指定dialect(mysql)。
2、當業務sql存在內部嵌套時,明確編寫sql分頁業務和與它對應的count查詢,別圖省事。
MyBatis工具 http://www.mybatis.tk
推薦使用 Mybatis 通用 Mapper3 https://github.com/abel533/Mapper
推薦使用 Mybatis 分頁插件 PageHelper https://github.com/pagehelper/Mybatis-PageHelper
推薦使用Mybatis介紹 http://www.mybatis.org/mybatis-3/zh/configuration.html#plugins