PageHelper和Mybatis-Plus分页

PageHelperMybatis-Plus 分页,两者都是基于 MyBatis 的拦截器机制来实现分页功能,通过拦截SQL语句并对其进行修改以实现分页。

PageHelper分页插件

在 MyBatis 中,当使用 PageHelper.startPage() 启动分页后,紧跟着的查询方法返回的 List 会被自动封装成一个 Page 对象。

使用

业务层直接调用 PageHelper.startPage(int pageNum, int pageSize) 传入分页参数(当前页码, 分页大小),PageHelper.startPage()之后紧跟查询方法即可。

PageHelper 的底层机制

基于 ThreadLocal 的分页参数传递

  • 调用 startPage() 时,分页参数(页码、每页条数等)会被存入当前线程的 ThreadLocal 变量中。
  • 后续的 MyBatis 查询方法会被 PageInterceptor(分页拦截器)拦截,从 ThreadLocal 中读取分页参数。

拦截器修改 SQL 并封装结果

  • 修改 SQL :拦截器根据分页参数,动态修改原始 SQL,添加数据库方言对应的分页语句(如 MySQL 的 LIMIT)。
  • 执行 COUNT 查询 :自动生成并执行 SELECT COUNT(*) 语句,获取总记录数。
  • 执行当前页查询:执行修改后的 SQL,获取当前页的数据。
  • 封装 Page 对象 :将分页数据和总记录数封装到 Page 对象中,最终返回给调用方。
  • 清理ThreadLocal :分页完成后,PageHelper会自动清除ThreadLocal中的分页参数,避免影响后续无关的查询。

Tips:

拦截器会将分页查询写回 startPage() 返回的 Page 对象中,即就是 PageHelper.startPage() 启动分页后,紧跟着的查询方法返回的 List 对象和 startPage() 返回的 Page 对象是同一个对象。见下图验证。

PagePageInfo对象

Page 对象

  • 本质PageArrayList 的子类,直接承载当前分页的数据集合(如当前页的查询结果列表)。

  • 功能

    • 存储当前页的数据(继承自 List)。
    • 包含基本的分页元数据,如:
      • pageNum:当前页码(从1开始)。
      • pageSize:每页显示条数。
      • total:总记录数(自动通过 COUNT 查询获取)。
      • pages:总页数(由 totalpageSize 计算得出)。
  • 特点

    • 直接关联查询结果 :分页查询后的 List 实际上是 Page 对象,可以直接强制转换获取分页元数据。
    • 轻量级:仅包含当前页数据和基础分页信息。

PageInfo 对象

  • 本质PageInfo 是对 Page增强封装,提供更丰富的分页元数据和工具方法。

  • 功能

    • 包含 Page 的所有分页元数据(如 pageNumpageSizetotal 等)。
    • 扩展了更多分页导航相关的属性,如:
      • isFirstPage/isLastPage:是否第一页/最后一页。
      • hasPreviousPage/hasNextPage:是否有上一页/下一页。
      • navigatePages:导航页码数量(如显示前5页、后5页)。
      • navigatepageNums:导航页码数组(用于生成页码按钮)。
      • prePage/nextPage:上一页/下一页的页码。
  • 特点

    • 脱离数据集合PageInfo 本身不直接存储数据集合,而是通过构造函数接收 List(通常是 Page 对象)来解析元数据。
    • 面向展示层 :更适合前端分页展示,直接提供导航所需的全部信息。

PageInfo 可以通过任何 List 构造,是因为Page对象继承自ArrayList,但实际只有分页后的 List(实际是 Page对象)才能正确解析分页元数据。

Mybatis-Plus分页

MyBatis-Plus 的分页功能基于拦截器实现,需手动配置分页插件。

使用

  • 创建 Page 对象:封装分页参数(当前页、每页条数)。
  • 执行分页查询 :调用MP提供的分页查询方法,传入 Page 和查询条件。
  • 获取分页结果 :返回的 Page 对象包含数据和分页信息。
Java 复制代码
public List<DeviceData> selectDeviceDataList(DeviceDataPageReqDto deviceData){
    Page<DeviceData> deviceDataPage = new Page<>(deviceData.getPageNum(), deviceData.getPageSize());
    this.lambdaQuery()
            .eq(ObjUtil.isNotNull(deviceData.getDeviceId()), DeviceData::getIotId, deviceData.getDeviceId())
            .eq(ObjUtil.isNotNull(deviceData.getFunctionId()), DeviceData::getFunctionId, deviceData.getFunctionId())
            .between(ObjUtil.isNotNull(deviceData.getStartTime()) && ObjUtil.isNotNull(deviceData.getEndTime()),
                    DeviceData::getAlarmTime, deviceData.getStartTime(), deviceData.getEndTime())
            // 执行分页查询
            .page(deviceDataPage);
    List<DeviceData> records = deviceDataPage.getRecords();
    long total = deviceDataPage.getTotal();
    // mapper层提供的分页查询方法示例
    // Page<DeviceData> deviceDataPage1 = deviceDataMapper.selectPage(deviceDataPage, new LambdaQueryWrapper<>());
    return records;
}

Tips:

只有在调用 MyBatis-Plus 的提供的分页方法方法时,分页插件才会生效,自动拦截和处理分页逻辑。

相关推荐
铁皮饭盒28 分钟前
Bun执行python代码
前端·javascript·后端
菜鸟谢1 小时前
Rust 枚举 (enum) 完整核心知识点
后端
晓杰在写后端1 小时前
从0到1实现Balatro游戏后端(9):Blind奖励结算与金币系统实现
后端·游戏开发
Patrick_Wilson1 小时前
幂等到底是什么?从前端视角讲透 SQL、HTTP 与 POST 接口的幂等设计
前端·后端·架构
凌览1 小时前
一人公司别再上 Jenkins,真不值
前端·后端
菜鸟谢1 小时前
Rust 元组与数组内存管理笔记
后端
oil欧哟1 小时前
Codex 最佳实践(超级长文):先搞懂 AI,再用好 AI
前端·人工智能·后端
AskHarries1 小时前
把一个外部系统接成 MCP 工具
后端·程序员
释然小师弟2 小时前
Android开发十年:反思与回顾
android·后端·嵌入式
雪隐2 小时前
个人电脑玩AI-04让5060 Ti给你打工——本地FLUX.2 Klein 的 AI 图片生成
人工智能·后端