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 的提供的分页方法方法时,分页插件才会生效,自动拦截和处理分页逻辑。

相关推荐
雪隐41 分钟前
个人电脑玩AI00-前言
人工智能·后端
我是一颗柠檬1 小时前
【Java后端技术亮点】动态路由权限(按钮级权限),细粒度控制到按钮级别
java·开发语言·后端·状态模式
前端Hardy1 小时前
CSS 动画真的比 JS 快?Josh Comeau 做了组实验,结果跟直觉不一样
前端·javascript·后端
Front思1 小时前
调取支付宝支付正式环境不可以唤起来,但是沙箱可以
后端
foggyprojects1 小时前
AI 生成 SQL 模板以后,为什么还需要固定 helper 规则
后端
明天一点1 小时前
Cloudflare 通知转发钉钉机器人
前端·后端
前端Hardy1 小时前
前端日历组件,要变天了?Schedule-X v4.6 彻底杀疯了
前端·javascript·后端
Oo_行者_oO1 小时前
微服务 Feign 从“万能公共服务”到“业务客户端”
后端·架构
wei_shuo1 小时前
别再踩坑了!KingbaseES 存储过程与触发器开发避坑实录
后端
元宝骑士1 小时前
MySQL 实战:跨表排序 + 指定类型置顶四种写法
后端·mysql