场景复现
数据库初始化有9条记录。当我通过分页插件去查询数据库时,查询第2页,每页10条记录时,查询的结果竟然有9条数据。结果显然不合理,因为我查询第2页,按照逻辑应该查询第11-20条记录,因此不存在,所以返回为空,但是现在却返回9条记录。
疑问如下:
- 为什么返回数据???
- 为什么返回9条数据???
解决办法
pagehelper:
# helperDialect: mysql
reasonable: false # 禁用合理化时,如果pageNum<1或pageNum>pages会返回空数据
源码分析
源码跟踪
直接定位到PageInterceptor的intercept方法
@Override
public Object intercept(Invocation invocation) throws Throwable {
try {
//省略内容,省略内容,省略内容
List resultList;
//步骤1:调用方法判断是否需要进行分页,如果不需要,直接返回结果
if (!dialect.skip(ms, parameter, rowBounds)) {
//判断是否需要进行 count 查询
if (dialect.beforeCount(ms, parameter, rowBounds)) {
//步骤2:查询总条数
Long count = count(executor, ms, parameter, rowBounds, resultHandler, boundSql);
//处理查询总数,返回 true 时继续分页查询,false 时直接返回
//步骤3:保存总条数
if (!dialect.afterCount(count, parameter, rowBounds)) {
//当查询总数为 0 时,直接返回空的结果
return dialect.afterPage(new ArrayList(), parameter, rowBounds);
}
}
//步骤4:执行分页查询
resultList = ExecutorUtil.pageQuery(dialect, executor,
ms, parameter, rowBounds, resultHandler, boundSql, cacheKey);
} else {
//rowBounds用参数值,不使用分页插件处理时,仍然支持默认的内存分页
resultList = executor.query(ms, parameter, rowBounds, resultHandler, cacheKey, boundSql);
}
//步骤5:封装结果
return dialect.afterPage(resultList, parameter, rowBounds);
} finally {
if(dialect != null){
dialect.afterAll();
}
}
}
我们看步骤3,保存总条数,总条数会保存到ThreadLocal的Page对象中,如图代码所示
//AbstractHelperDialect的afterCount方法
public boolean afterCount(long count, Object parameterObject, RowBounds rowBounds) {
Page page = getLocalPage();
//(重点,重点,重点)把count保存到page对象中
page.setTotal(count);
if (rowBounds instanceof PageRowBounds) {
((PageRowBounds) rowBounds).setTotal(count);
}
//pageSize < 0 的时候,不执行分页查询
//pageSize = 0 的时候,还需要执行后续查询,但是不会分页
if (page.getPageSize() < 0) {
return false;
}
return count > ((page.getPageNum() - 1) * page.getPageSize());
}
重点来了,我们跟进Page的setTotal方法
//Page###setTotal
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) {
if(pages!=0){
//把pageNum设置为最后一页,震惊
//把pageNum设置为最后一页,震惊
//把pageNum设置为最后一页,震惊
pageNum = pages;
}
calculateStartAndEndRow();
}
}
问题解析
为什么返回数据???
因为我查询的页数(pageNum = 2)大于总页数(pages = 1),因此把pages赋值给pageNum,查询最后一页肯定有数据===!
为什么返回9条数据???
因为我查询的页数(pageNum = 2)大于总页数(pages = 1),因此把pages赋值给pageNum,查询最后一页根据分析就是9条===!