研发效能 得嘞,分页插件 PageHelper 返回记录总数 total 竟然出错了!

京东云开发者 · 2024年03月20日 · 1588 次阅读

问题描述
分页返回的记录总数 total 和每页数量 pageSize 一致,数据库统计的数量大于当前返回的总记录数 total,以下是相关代码

问题分析
sql 错误导致返回信息有误?
检查结果:经过数据执行日志中生成的 sql,sql 正常并且数据总条数也正确

PageHelper 使用方式错误,导致数据错误
检查结果:通过与项目中其他地方使用记录的对比,使用方式正确

返回结果后有中间处理导致总数减少
检查结果:网上有人遇到 对返回结果有类型转化导致 total 错误的情况, 以此类推,发现当前代码虽没有对返回结果进行类型转换但是对 mapper 返回的结果更换了实例对象然后将更换后的对象包装,

进一步查看包装成 PageInfo时源码并没有关于 total 参数的处理,

PageInfo构造方法

public class PageInfo extends PageSerializable {
/**

  • 包装 Page 对象 *
  • @param list page 结果
  • @param navigatePages 页码数量
    */
    public PageInfo(List list, int navigatePages) {
    super(list);
    if (list instanceof Page) {
    Page page = (Page) list;
    this.pageNum = page.getPageNum();
    this.pageSize = page.getPageSize();

    this.pages = page.getPages();
    this.size = page.size();
    //由于结果是>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.size = list.size();
    this.startRow = 0;
    this.endRow = list.size() > 0 ? list.size() - 1 : 0;
    }
    if (list instanceof Collection) {
    this.navigatePages = navigatePages;
    //计算导航页
    calcNavigatepageNums();
    //计算前后页,第一页,最后一页
    calcPage();
    //判断页面边界
    judgePageBoudary();
    }
    }
    }
    继续查看父类 PageSerializable,发现有关于 total 参数的处理,即 mapper 返回的 list 不是 Page 的实例时 total 会被设置为返回 list 的 size 大小

PageSerializable 构造方法

public PageSerializable(List list) {
this.list = list;
if(list instanceof Page){
this.total = ((Page) list).getTotal();
} else {
this.total = list.size();
}
}
进一步 debug,发现返回 list 确实不是 Page 类的实例,故推断出这一结果是由于对 mapper 返回 list 结果更换了实例对象导致的,

再次确认 mapper 返回结果,是 Page 的实例

解决方案
使用 mapper 返回的对象直接构造 PageInfo 对象,并在此基础上获取分页信息

更正的代码如下:

最佳实践
在使用 PageInfo pageInfo = new PageInfo<>(T); 构造 PageInfo 时直接使用 mapper 返回对象,不要进行类型转换或转存等操作,以免丢失数据。

暂无回复。
需要 登录 后方可回复, 如果你还没有账号请点击这里 注册