前言
在之前的文章 MyBatis源碼閱讀——MyBatis插件原理中我們已經知道MyBatis的插件是如何運行的,這篇文章中,我們將去了解MyBatis常用插件com.github.pagehelper.PageHelper的實現過程
示例代碼
PageHelper攔截過程
設置完成後,Executor的每個method = “query” 的方法執行都會被代理執行
PageHelper.java->intercept()
/**
* Mybatis攔截器方法
*
* @param invocation 攔截器入參
* @return 返回執行結果
* @throws Throwable 拋出異常
*/
public Object intercept(Invocation invocation) throws Throwable {
if (autoDialect) {
initSqlUtil(invocation);
}
return sqlUtil.processPage(invocation);
}
sqlUtil.processPage(invocation)
/**
* Mybatis攔截器方法
*
* @param invocation 攔截器入參
* @return 返回執行結果
* @throws Throwable 拋出異常
*/
private Object _processPage(Invocation invocation) throws Throwable {
final Object[] args = invocation.getArgs();
RowBounds rowBounds = (RowBounds) args[2];
if (SqlUtil.getLocalPage() == null && rowBounds == RowBounds.DEFAULT) {
if (OrderByHelper.getOrderBy() != null) {
OrderByHelper.processIntercept(invocation);
}
return invocation.proceed();
} else {
//獲取原始的ms
MappedStatement ms = (MappedStatement) args[0];
//判斷並處理爲PageSqlSource
if (!isPageSqlSource(ms)) {
processMappedStatement(ms, parser);
}
//忽略RowBounds-否則會進行Mybatis自帶的內存分頁
args[2] = RowBounds.DEFAULT;
//分頁信息
Page page = getPage(rowBounds);
//pageSizeZero的判斷
if ((page.getPageSizeZero() != null && page.getPageSizeZero()) && page.getPageSize() == 0) {
COUNT.set(null);
//執行正常(不分頁)查詢
Object result = invocation.proceed();
//得到處理結果
page.addAll((List) result);
//相當於查詢第一頁
page.setPageNum(1);
//這種情況相當於pageSize=total
page.setPageSize(page.size());
//仍然要設置total
page.setTotal(page.size());
//返回結果仍然爲Page類型 - 便於後面對接收類型的統一處理
return page;
}
//簡單的通過total的值來判斷是否進行count查詢
if (page.isCount()) {
COUNT.set(Boolean.TRUE);
//替換MS
args[0] = msCountMap.get(ms.getId());
//查詢總數
Object result = invocation.proceed();
//還原ms
args[0] = ms;
//設置總數
page.setTotal((Integer) ((List) result).get(0));
if (page.getTotal() == 0) {
return page;
}
}
//pageSize>0的時候執行分頁查詢,pageSize<=0的時候不執行相當於可能只返回了一個count
if (page.getPageSize() > 0 &&
((rowBounds == RowBounds.DEFAULT && page.getPageNum() > 0)
|| rowBounds != RowBounds.DEFAULT)) {
//將參數中的MappedStatement替換爲新的qs
COUNT.set(null);
BoundSql boundSql = ms.getBoundSql(args[1]);
args[1] = parser.setPageParameter(ms, args[1], boundSql, page);
COUNT.set(Boolean.FALSE);
//執行分頁查詢
Object result = invocation.proceed();
//得到處理結果
page.addAll((List) result);
}
//返回結果
return page;
}
}