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

相关推荐
程序员鱼皮44 分钟前
我代表编程导航,向大家道歉!
前端·后端·程序员
zjjuejin1 小时前
Maven 生命周期与插件机制
后端·maven
阿杆1 小时前
为什么我建议你把自建 Redis 迁移到云上进行托管
redis·后端
Java水解1 小时前
go语言教程(全网最全,持续更新补全)
后端·go
bobz9652 小时前
QEMU 使用 DPDK 时候在 libvirt xml 中设置 sock 的目的
后端
thinktik2 小时前
AWS EKS 计算资源自动扩缩之按需申请Fargate[AWS 中国宁夏区]
后端·aws
thinktik2 小时前
AWS EKS 实现底层EC2计算资源的自动扩缩[AWS 中国宁夏区]
后端·aws
uhakadotcom2 小时前
什么是OpenTelemetry?
后端·面试·github
知其然亦知其所以然2 小时前
MySQL 社招必考题:如何优化特定类型的查询语句?
后端·mysql·面试
用户4099322502122 小时前
给接口加新字段又不搞崩老客户端?FastAPI的多版本API靠哪三招实现?
后端·ai编程·trae