MyBatis分頁外掛PageHelper的使用
準備工作
在pom.ml中引入依賴
<!-- https://mvnrepository.com/artifact/com.github.pagehelper/pagehelper-spring-boot-starter --> <dependency> <groupId>com.github.pagehelper</groupId> <artifactId>pagehelper-spring-boot-starter</artifactId> <version>1.2.3</version> <exclusions> <exclusion> <artifactId>mybatis-spring-boot-starter</artifactId> <groupId>org.mybatis.spring.boot</groupId> </exclusion> </exclusions> </dependency>
注:如果引入了mybatis-spring-boot-starter依賴,那麼可以不引入pagehelper依賴,因為mybatis-spring-boot-starter 會自動引入pagehelper。
注:除了分頁外掛依賴外,還需要引入相關的連線資料庫的包,這裡本人就不一一給出了。
分頁外掛的使用
Postman訪問一下localhost:8080/pageHelperTest?pageNum=2&pageSize=2,PageInfo返回給前端的json資料 是這樣的:
到這裡為止,分頁外掛的簡單使用就結束了,下面進行一些分析。
外掛的邏輯思路(簡單)分析
在PageHelper的使用中,核心的即為:
注:我們可以在Controller層中使用分頁外掛;也可以在Service層中使用分頁外掛;如果只是簡單的查詢的話, 在Controller層中使用分頁外掛就可以了;如果是比較複雜的查詢的話,那麼最好在Service層中使用分頁外掛。
注:PageHelper.startPage(pageNum, pageSize);語句之後,第一個SQL語句,必須為要進行分頁的(全)查詢語句。 追注:如果在PageHelper.startPage()方法之後,先執行了其他的sql語句,然後再執行的要分頁的查詢的話;那麼分頁 會失效。
提示:雖然我們在PageHelper.startPage()之後,沒有什麼操作空間(必須保證其後的第一個SQL語句為要分頁的SQL查 詢語句);但是在我們將Page查詢出來之後(此時已經進行過分頁了),我們可以對查詢結果再處理;無論是將 Page包裝為PageInfo返回給前端還是直接返回Page給前端,或者是將Page中的資訊get出來,set進我們自定義 的類並返回給前端之前,我們可以對查詢出來的資訊再處理,然後再返回。
核心流程分析
PageHelper.startPage()返回一個Page<E>例項,Page<E>繼承了ArrayList<E>,在PageHelper.startPage() 後面的第一個SQL,會被public class PageInterceptor implements Interceptor類攔截處理,進而實現分頁查詢等 功能;其將查詢的結果封裝進了Page<E>中,並返回。
注意:PageHelper.startPage()獲得的Page<E>例項引用也指向查詢結果,所以我們其實可以不需要用集合來接 查詢結果,執行查詢語句後,直接使用PageHelper.startPage()返回的Page<E>例項,也能從中獲取到查詢結果。 所以上面的核心程式碼處也可以這麼寫:
在new PageInfo<>(list)時,其建構函式中會判斷傳入的list是否為Page的引用,如果是的話,又會將list拆箱轉 型為Page,然後再將Page封裝為PageInfo。
注:PageInfo是比Page資訊更豐富的一個類;我們可以直接返回Page,也可以使用PageInfo包裝一下返回PageInfo, 甚至也可以自定義一個類來存放結果資訊(只需將返回的Page中的資訊取出來,再setter放入我們自己的類即可)。 我們可以這樣取,如(給出部分示例):
給出三個本人覺得比較核心的類(感興趣的小夥伴也可以自己打斷點跟蹤原始碼)
Page:
package com.github.pagehelper;
import java.io.Closeable;
import java.util.ArrayList;
import java.util.List;
/**
* Mybatis - 分頁物件
*
* @author liuzh/abel533/isea533
* @version 3.6.0
* 專案地址 : http://git.oschina.net/free/Mybatis_PageHelper
*/
public class Page<E> extends ArrayList<E> implements Closeable {
private static final long serialVersionUID = 1L;
/**
* 頁碼,從1開始
*/
private int pageNum;
/**
* 頁面大小
*/
private int pageSize;
/**
* 起始行
*/
private int startRow;
/**
* 末行
*/
private int endRow;
/**
* 總數
*/
private long total;
/**
* 總頁數
*/
private int pages;
/**
* 包含count查詢
*/
private boolean count = true;
/**
* 分頁合理化
*/
private Boolean reasonable;
/**
* 當設定為true的時候,如果pagesize設定為0(或RowBounds的limit=0),就不執行分頁,返回全部結果
*/
private Boolean pageSizeZero;
/**
* 進行count查詢的列名
*/
private String countColumn;
/**
* 排序
*/
private String orderBy;
/**
* 只增加排序
*/
private boolean orderByOnly;
public Page() {
super();
}
public Page(int pageNum, int pageSize) {
this(pageNum, pageSize, true, null);
}
public Page(int pageNum, int pageSize, boolean count) {
this(pageNum, pageSize, count, null);
}
private Page(int pageNum, int pageSize, boolean count, Boolean reasonable) {
super(0);
if (pageNum == 1 && pageSize == Integer.MAX_VALUE) {
pageSizeZero = true;
pageSize = 0;
}
this.pageNum = pageNum;
this.pageSize = pageSize;
this.count = count;
calculateStartAndEndRow();
setReasonable(reasonable);
}
/**
* int[] rowBounds
* 0 : offset
* 1 : limit
*/
public Page(int[] rowBounds, boolean count) {
super(0);
if (rowBounds[0] == 0 && rowBounds[1] == Integer.MAX_VALUE) {
pageSizeZero = true;
this.pageSize = 0;
} else {
this.pageSize = rowBounds[1];
this.pageNum = rowBounds[1] != 0 ? (int) (Math.ceil(((double) rowBounds[0] + rowBounds[1]) / rowBounds[1])) : 0;
}
this.startRow = rowBounds[0];
this.count = count;
this.endRow = this.startRow + rowBounds[1];
}
public List<E> getResult() {
return this;
}
public int getPages() {
return pages;
}
public Page<E> setPages(int pages) {
this.pages = pages;
return this;
}
public int getEndRow() {
return endRow;
}
public Page<E> setEndRow(int endRow) {
this.endRow = endRow;
return this;
}
public int getPageNum() {
return pageNum;
}
public Page<E> setPageNum(int pageNum) {
//分頁合理化,針對不合理的頁碼自動處理
this.pageNum = ((reasonable != null && reasonable) && pageNum <= 0) ? 1 : pageNum;
return this;
}
public int getPageSize() {
return pageSize;
}
public Page<E> setPageSize(int pageSize) {
this.pageSize = pageSize;
return this;
}
public int getStartRow() {
return startRow;
}
public Page<E> setStartRow(int startRow) {
this.startRow = startRow;
return this;
}
public long getTotal() {
return total;
}
public void setTotal(long total) {
this.total = total;
if (total == -1) {
pages = 1;
return;
}
if (pageSize > 0) {
pages = (int) (total / pageSize + ((total % pageSize == 0) ? 0 : 1));
} else {
pages = 0;
}
//分頁合理化,針對不合理的頁碼自動處理
if ((reasonable != null && reasonable) && pageNum > pages) {
pageNum = pages;
calculateStartAndEndRow();
}
}
public Boolean getReasonable() {
return reasonable;
}
public Page<E> setReasonable(Boolean reasonable) {
if (reasonable == null) {
return this;
}
this.reasonable = reasonable;
//分頁合理化,針對不合理的頁碼自動處理
if (this.reasonable && this.pageNum <= 0) {
this.pageNum = 1;
calculateStartAndEndRow();
}
return this;
}
public Boolean getPageSizeZero() {
return pageSizeZero;
}
public Page<E> setPageSizeZero(Boolean pageSizeZero) {
if (pageSizeZero != null) {
this.pageSizeZero = pageSizeZero;
}
return this;
}
public String getOrderBy() {
return orderBy;
}
public <E> Page<E> setOrderBy(String orderBy) {
this.orderBy = orderBy;
return (Page<E>) this;
}
public boolean isOrderByOnly() {
return orderByOnly;
}
public void setOrderByOnly(boolean orderByOnly) {
this.orderByOnly = orderByOnly;
}
/**
* 計算起止行號
*/
private void calculateStartAndEndRow() {
this.startRow = this.pageNum > 0 ? (this.pageNum - 1) * this.pageSize : 0;
this.endRow = this.startRow + this.pageSize * (this.pageNum > 0 ? 1 : 0);
}
public boolean isCount() {
return this.count;
}
public Page<E> setCount(boolean count) {
this.count = count;
return this;
}
/**
* 設定頁碼
*
* @param pageNum
* @return
*/
public Page<E> pageNum(int pageNum) {
//分頁合理化,針對不合理的頁碼自動處理
this.pageNum = ((reasonable != null && reasonable) && pageNum <= 0) ? 1 : pageNum;
return this;
}
/**
* 設定頁面大小
*
* @param pageSize
* @return
*/
public Page<E> pageSize(int pageSize) {
this.pageSize = pageSize;
calculateStartAndEndRow();
return this;
}
/**
* 是否執行count查詢
*
* @param count
* @return
*/
public Page<E> count(Boolean count) {
this.count = count;
return this;
}
/**
* 設定合理化
*
* @param reasonable
* @return
*/
public Page<E> reasonable(Boolean reasonable) {
setReasonable(reasonable);
return this;
}
/**
* 當設定為true的時候,如果pagesize設定為0(或RowBounds的limit=0),就不執行分頁,返回全部結果
*
* @param pageSizeZero
* @return
*/
public Page<E> pageSizeZero(Boolean pageSizeZero) {
setPageSizeZero(pageSizeZero);
return this;
}
/**
* 指定 count 查詢列
*
* @param columnName
* @return
*/
public Page<E> countColumn(String columnName) {
this.countColumn = columnName;
return this;
}
/**
* 轉換為PageInfo
*
* @return
*/
public PageInfo<E> toPageInfo() {
PageInfo<E> pageInfo = new PageInfo<E>(this);
return pageInfo;
}
public <E> Page<E> doSelectPage(ISelect select) {
select.doSelect();
return (Page<E>) this;
}
public <E> PageInfo<E> doSelectPageInfo(ISelect select) {
select.doSelect();
return (PageInfo<E>) this.toPageInfo();
}
public long doCount(ISelect select) {
this.pageSizeZero = true;
this.pageSize = 0;
select.doSelect();
return this.total;
}
public String getCountColumn() {
return countColumn;
}
public void setCountColumn(String countColumn) {
this.countColumn = countColumn;
}
@Override
public String toString() {
return "Page{" +
"count=" + count +
", pageNum=" + pageNum +
", pageSize=" + pageSize +
", startRow=" + startRow +
", endRow=" + endRow +
", total=" + total +
", pages=" + pages +
", reasonable=" + reasonable +
", pageSizeZero=" + pageSizeZero +
'}';
}
@Override
public void close() {
PageHelper.clearPage();
}
}
PageInfo:
package com.github.pagehelper;
import java.io.Serializable;
import java.util.Collection;
import java.util.List;
/**
* 對Page<E>結果進行包裝
* <p/>
* 新增分頁的多項屬性,主要參考:http://bbs.csdn.net/topics/360010907
*
* @author liuzh/abel533/isea533
* @version 3.3.0
* @since 3.2.2
* 專案地址 : http://git.oschina.net/free/Mybatis_PageHelper
*/
@SuppressWarnings({"rawtypes", "unchecked"})
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();
}
}
/**
* 計算導航頁
*/
private void calcNavigatepageNums() {
//當總頁數小於或等於導航頁碼數時
if (pages <= navigatePages) {
navigatepageNums = new int[pages];
for (int i = 0; i < pages; i++) {
navigatepageNums[i] = i + 1;
}
} else { //當總頁數大於導航頁碼數時
navigatepageNums = new int[navigatePages];
int startNum = pageNum - navigatePages / 2;
int endNum = pageNum + navigatePages / 2;
if (startNum < 1) {
startNum = 1;
//(最前navigatePages頁
for (int i = 0; i < navigatePages; i++) {
navigatepageNums[i] = startNum++;
}
} else if (endNum > pages) {
endNum = pages;
//最後navigatePages頁
for (int i = navigatePages - 1; i >= 0; i--) {
navigatepageNums[i] = endNum--;
}
} else {
//所有中間頁
for (int i = 0; i < navigatePages; i++) {
navigatepageNums[i] = startNum++;
}
}
}
}
/**
* 計算前後頁,第一頁,最後一頁
*/
private void calcPage() {
if (navigatepageNums != null && navigatepageNums.length > 0) {
navigateFirstPage = navigatepageNums[0];
navigateLastPage = navigatepageNums[navigatepageNums.length - 1];
if (pageNum > 1) {
prePage = pageNum - 1;
}
if (pageNum < pages) {
nextPage = pageNum + 1;
}
}
}
/**
* 判定頁面邊界
*/
private void judgePageBoudary() {
isFirstPage = pageNum == 1;
isLastPage = pageNum == pages || pages == 0;;
hasPreviousPage = pageNum > 1;
hasNextPage = pageNum < pages;
}
public int getPageNum() {
return pageNum;
}
public void setPageNum(int pageNum) {
this.pageNum = pageNum;
}
public int getPageSize() {
return pageSize;
}
public void setPageSize(int pageSize) {
this.pageSize = pageSize;
}
public int getSize() {
return size;
}
public void setSize(int size) {
this.size = size;
}
public int getStartRow() {
return startRow;
}
public void setStartRow(int startRow) {
this.startRow = startRow;
}
public int getEndRow() {
return endRow;
}
public void setEndRow(int endRow) {
this.endRow = endRow;
}
public long getTotal() {
return total;
}
public void setTotal(long total) {
this.total = total;
}
public int getPages() {
return pages;
}
public void setPages(int pages) {
this.pages = pages;
}
public List<T> getList() {
return list;
}
public void setList(List<T> list) {
this.list = list;
}
@Deprecated
// firstPage就是1, 此函式獲取的是導航條上的第一頁, 容易產生歧義
public int getFirstPage() {
return navigateFirstPage;
}
@Deprecated
public void setFirstPage(int firstPage) {
this.navigateFirstPage = firstPage;
}
public int getPrePage() {
return prePage;
}
public void setPrePage(int prePage) {
this.prePage = prePage;
}
public int getNextPage() {
return nextPage;
}
public void setNextPage(int nextPage) {
this.nextPage = nextPage;
}
@Deprecated
// 請用getPages()來獲取最後一頁, 此函式獲取的是導航條上的最後一頁, 容易產生歧義.
public int getLastPage() {
return navigateLastPage;
}
@Deprecated
public void setLastPage(int lastPage) {
this.navigateLastPage = lastPage;
}
public boolean isIsFirstPage() {
return isFirstPage;
}
public void setIsFirstPage(boolean isFirstPage) {
this.isFirstPage = isFirstPage;
}
public boolean isIsLastPage() {
return isLastPage;
}
public void setIsLastPage(boolean isLastPage) {
this.isLastPage = isLastPage;
}
public boolean isHasPreviousPage() {
return hasPreviousPage;
}
public void setHasPreviousPage(boolean hasPreviousPage) {
this.hasPreviousPage = hasPreviousPage;
}
public boolean isHasNextPage() {
return hasNextPage;
}
public void setHasNextPage(boolean hasNextPage) {
this.hasNextPage = hasNextPage;
}
public int getNavigatePages() {
return navigatePages;
}
public void setNavigatePages(int navigatePages) {
this.navigatePages = navigatePages;
}
public int[] getNavigatepageNums() {
return navigatepageNums;
}
public void setNavigatepageNums(int[] navigatepageNums) {
this.navigatepageNums = navigatepageNums;
}
public int getNavigateFirstPage() {
return navigateFirstPage;
}
public int getNavigateLastPage() {
return navigateLastPage;
}
public void setNavigateFirstPage(int navigateFirstPage) {
this.navigateFirstPage = navigateFirstPage;
}
public void setNavigateLastPage(int navigateLastPage) {
this.navigateLastPage = navigateLastPage;
}
@Override
public String toString() {
final StringBuffer sb = new StringBuffer("PageInfo{");
sb.append("pageNum=").append(pageNum);
sb.append(", pageSize=").append(pageSize);
sb.append(", size=").append(size);
sb.append(", startRow=").append(startRow);
sb.append(", endRow=").append(endRow);
sb.append(", total=").append(total);
sb.append(", pages=").append(pages);
sb.append(", list=").append(list);
sb.append(", prePage=").append(prePage);
sb.append(", nextPage=").append(nextPage);
sb.append(", isFirstPage=").append(isFirstPage);
sb.append(", isLastPage=").append(isLastPage);
sb.append(", hasPreviousPage=").append(hasPreviousPage);
sb.append(", hasNextPage=").append(hasNextPage);
sb.append(", navigatePages=").append(navigatePages);
sb.append(", navigateFirstPage=").append(navigateFirstPage);
sb.append(", navigateLastPage=").append(navigateLastPage);
sb.append(", navigatepageNums=");
if (navigatepageNums == null) sb.append("null");
else {
sb.append('[');
for (int i = 0; i < navigatepageNums.length; ++i)
sb.append(i == 0 ? "" : ", ").append(navigatepageNums[i]);
sb.append(']');
}
sb.append('}');
return sb.toString();
}
}
PageInterceptor:
package com.github.pagehelper;
import com.github.pagehelper.cache.Cache;
import com.github.pagehelper.cache.CacheFactory;
import com.github.pagehelper.util.MSUtils;
import com.github.pagehelper.util.StringUtil;
import org.apache.ibatis.cache.CacheKey;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;
import java.lang.reflect.Field;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Properties;
/**
* 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 {
try {
Object[] args = invocation.getArgs();
MappedStatement ms = (MappedStatement) args[0];
Object parameter = args[1];
RowBounds rowBounds = (RowBounds) args[2];
ResultHandler resultHandler = (ResultHandler) args[3];
Executor executor = (Executor) invocation.getTarget();
CacheKey cacheKey;
BoundSql boundSql;
//由於邏輯關係,只會進入一次
if(args.length == 4){
//4 個引數時
boundSql = ms.getBoundSql(parameter);
cacheKey = executor.createCacheKey(ms, parameter, rowBounds, boundSql);
} else {
//6 個引數時
cacheKey = (CacheKey) args[4];
boundSql = (BoundSql) args[5];
}
List resultList;
//呼叫方法判斷是否需要進行分頁,如果不需要,直接返回結果
if (!dialect.skip(ms, parameter, rowBounds)) {
//反射獲取動態引數
String msId = ms.getId();
Configuration configuration = ms.getConfiguration();
Map<String, Object> additionalParameters = (Map<String, Object>) additionalParametersField.get(boundSql);
//判斷是否需要進行 count 查詢
if (dialect.beforeCount(ms, parameter, rowBounds)) {
String countMsId = msId + countSuffix;
Long count;
//先判斷是否存在手寫的 count 查詢
MappedStatement countMs = getExistedMappedStatement(configuration, countMsId);
if(countMs != null){
count = executeManualCount(executor, countMs, parameter, boundSql, resultHandler);
} else {
countMs = msCountMap.get(countMsId);
//自動建立
if (countMs == null) {
//根據當前的 ms 建立一個返回值為 Long 型別的 ms
countMs = MSUtils.newCountMappedStatement(ms, countMsId);
msCountMap.put(countMsId, countMs);
}
count = executeAutoCount(executor, countMs, parameter, boundSql, rowBounds, resultHandler);
}
//處理查詢總數
//返回 true 時繼續分頁查詢,false 時直接返回
if (!dialect.afterCount(count, parameter, rowBounds)) {
//當查詢總數為 0 時,直接返回空的結果
return dialect.afterPage(new ArrayList(), parameter, rowBounds);
}
}
//判斷是否需要進行分頁查詢
if (dialect.beforePage(ms, parameter, rowBounds)) {
//生成分頁的快取 key
CacheKey pageKey = cacheKey;
//處理引數物件
parameter = dialect.processParameterObject(ms, parameter, boundSql, pageKey);
//呼叫方言獲取分頁 sql
String pageSql = dialect.getPageSql(ms, boundSql, parameter, rowBounds, pageKey);
BoundSql pageBoundSql = new BoundSql(configuration, pageSql, boundSql.getParameterMappings(), parameter);
//設定動態引數
for (String key : additionalParameters.keySet()) {
pageBoundSql.setAdditionalParameter(key, additionalParameters.get(key));
}
//執行分頁查詢
resultList = executor.query(ms, parameter, RowBounds.DEFAULT, resultHandler, pageKey, pageBoundSql);
} else {
//不執行分頁的情況下,也不執行記憶體分頁
resultList = executor.query(ms, parameter, RowBounds.DEFAULT, resultHandler, cacheKey, boundSql);
}
} else {
//rowBounds用引數值,不使用分頁外掛處理時,仍然支援預設的記憶體分頁
resultList = executor.query(ms, parameter, rowBounds, resultHandler, cacheKey, boundSql);
}
return dialect.afterPage(resultList, parameter, rowBounds);
} finally {
dialect.afterAll();
}
}
/**
* 執行手動設定的 count 查詢,該查詢支援的引數必須和被分頁的方法相同
*
* @param executor
* @param countMs
* @param parameter
* @param boundSql
* @param resultHandler
* @return
* @throws IllegalAccessException
* @throws SQLException
*/
private Long executeManualCount(Executor executor, MappedStatement countMs,
Object parameter, BoundSql boundSql,
ResultHandler resultHandler) throws IllegalAccessException, SQLException {
CacheKey countKey = executor.createCacheKey(countMs, parameter, RowBounds.DEFAULT, boundSql);
BoundSql countBoundSql = countMs.getBoundSql(parameter);
Object countResultList = executor.query(countMs, parameter, RowBounds.DEFAULT, resultHandler, countKey, countBoundSql);
Long count = ((Number) ((List) countResultList).get(0)).longValue();
return count;
}
/**
* 執行自動生成的 count 查詢
*
* @param executor
* @param countMs
* @param parameter
* @param boundSql
* @param rowBounds
* @param resultHandler
* @return
* @throws IllegalAccessException
* @throws SQLException
*/
private Long executeAutoCount(Executor executor, MappedStatement countMs,
Object parameter, BoundSql boundSql,
RowBounds rowBounds, ResultHandler resultHandler) throws IllegalAccessException, SQLException {
Map<String, Object> additionalParameters = (Map<String, Object>) additionalParametersField.get(boundSql);
//建立 count 查詢的快取 key
CacheKey countKey = executor.createCacheKey(countMs, parameter, RowBounds.DEFAULT, boundSql);
//呼叫方言獲取 count sql
String countSql = dialect.getCountSql(countMs, boundSql, parameter, rowBounds, countKey);
//countKey.update(countSql);
BoundSql countBoundSql = new BoundSql(countMs.getConfiguration(), countSql, boundSql.getParameterMappings(), parameter);
//當使用動態 SQL 時,可能會產生臨時的引數,這些引數需要手動設定到新的 BoundSql 中
for (String key : additionalParameters.keySet()) {
countBoundSql.setAdditionalParameter(key, additionalParameters.get(key));
}
//執行 count 查詢
Object countResultList = executor.query(countMs, parameter, RowBounds.DEFAULT, resultHandler, countKey, countBoundSql);
Long count = (Long) ((List) countResultList).get(0);
return count;
}
/**
* 嘗試獲取已經存在的在 MS,提供對手寫count和page的支援
*
* @param configuration
* @param msId
* @return
*/
private MappedStatement getExistedMappedStatement(Configuration configuration, String msId){
MappedStatement mappedStatement = null;
try {
mappedStatement = configuration.getMappedStatement(msId, false);
} catch (Throwable t){
//ignore
}
return mappedStatement;
}
@Override
public Object plugin(Object target) {
//TODO Spring bean 方式配置時,如果沒有配置屬性就不會執行下面的 setProperties 方法,就不會初始化,因此考慮在這個方法中做一次判斷和初始化
//TODO https://github.com/pagehelper/Mybatis-PageHelper/issues/26
return Plugin.wrap(target, this);
}
@Override
public void setProperties(Properties properties) {
//快取 count ms
msCountMap = CacheFactory.createCache(properties.getProperty("msCountCache"), "ms", properties);
String dialectClass = properties.getProperty("dialect");
if (StringUtil.isEmpty(dialectClass)) {
dialectClass = default_dialect_class;
}
try {
Class<?> aClass = Class.forName(dialectClass);
dialect = (Dialect) aClass.newInstance();
} catch (Exception e) {
throw new PageException(e);
}
dialect.setProperties(properties);
String countSuffix = properties.getProperty("countSuffix");
if (StringUtil.isNotEmpty(countSuffix)) {
this.countSuffix = countSuffix;
}
try {
//反射獲取 BoundSql 中的 additionalParameters 屬性
additionalParametersField = BoundSql.class.getDeclaredField("additionalParameters");
additionalParametersField.setAccessible(true);
} catch (NoSuchFieldException e) {
throw new PageException(e);
}
}
}