本次我们分析PageHelper的源码,查看它的执行过程;
1、PageHelper的版本
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>3.7.5</version>
</dependency>
2、首先我们先看在代码中怎么使用的
PageHelper.startPage(1,2);
List<User> users = sqlSession.selectList("UserMapper.queryAllUser");
users.forEach(u -> System.out.println(u));
3、分析PageHelper.startPage(1,2),这个是在设置当前页和每页查询的数据量
PageHelper里面有一个静态方法:
public static Page startPage(int pageNum, int pageSize) {
return startPage(pageNum, pageSize, true);
}
最后调用的方法:
public static Page startPage(int pageNum, int pageSize, boolean count, Boolean reasonable, Boolean pageSizeZero) {
Page page = new Page(pageNum, pageSize, count);
page.setReasonable(reasonable);
page.setPageSizeZero(pageSizeZero);
SqlUtil.setLocalPage(page);
return page;
}
其实就是创建了一个Page对象,设置一些参数,然后把Page对象放入了ThreadLocal对象里面。
创建对象的时候还计算了开始和结束的行
private Page(int pageNum, int pageSize, int total, Boolean reasonable) {
super(0);
if (pageNum == 1 && pageSize == Integer.MAX_VALUE) {
pageSizeZero = true;
pageSize = 0;
}
this.pageNum = pageNum;
this.pageSize = pageSize;
this.total = total;
calculateStartAndEndRow();// 计算起止行号
setReasonable(reasonable);
}
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);
}
// 将创建的page对象放入了ThreadLocal对象中
SqlUtil.setLocalPage(page);
public static void setLocalPage(Page page) {
LOCAL_PAGE.set(page);
}
private static final ThreadLocal<Page> LOCAL_PAGE = new ThreadLocal<Page>();
4、PageHelper实现Interceptor接口,在接口上面有一个注解:
@Intercepts(@Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class}));意思也就是说拦截了Executor的query方法,方法的参数是:MappedStatement,Object,RowBounds,ResultHandler。
实现Interceptor接口会重写3个方法:
/**
* Mybatis拦截器方法
*
* @param invocation 拦截器入参
* @return 返回执行结果
* @throws Throwable 抛出异常
*/
public Object intercept(Invocation invocation) throws Throwable {
return sqlUtil.processPage(invocation);
}
/**
* 只拦截Executor
*
* @param target
* @return
*/
public Object plugin(Object target) {
if (target instanceof Executor) {
return Plugin.wrap(target, this);
} else {
return target;
}
}
/**
* 设置属性值
*
* @param p 属性值
*/
public void setProperties(Properties p) {
//MyBatis3.2.0版本校验
try {
Class.forName("org.apache.ibatis.scripting.xmltags.SqlNode");//SqlNode是3.2.0之后新增的类
} catch (ClassNotFoundException e) {
throw new RuntimeException("您使用的MyBatis版本太低,MyBatis分页插件PageHelper支持MyBatis3.2.0及以上版本!");
}
//数据库方言
String dialect = p.getPro