PageHelper 全面讲解(MyBatis 分页神器)

张开发
2026/6/7 18:03:03 15 分钟阅读
PageHelper 全面讲解(MyBatis 分页神器)
PageHelper是MyBatis 生态中最流行的物理分页插件核心作用自动拦截 SQL 并添加分页语法如 MySQL 的 LIMIT实现物理分页只查当前页数据性能远优于 MyBatis 自带的 RowBounds 内存分页。它通过 MyBatis 的拦截器机制工作无需修改原始 SQL 语句极大简化分页开发一、核心概念物理分页 vs 内存分页特性物理分页PageHelper内存分页RowBounds查询方式只查询当前页数据如 LIMIT 0,10查询全表数据后在内存中截取性能高效数据量大时优势明显低效数据量大时 OOM 风险适用场景所有生产环境特别是大数据量仅小数据量测试场景实现方式数据库层面SQL 级应用层面Java 级一、基础用法3 步搞定分页1. 核心 APIPageHelper.startPage()在查询前调用为当前线程开启分页上下文// 1. 开启分页第1页每页10条 PageHelper.startPage(1, 10); // 2. 执行正常查询PageHelper会自动拦截并添加分页SQL ListUser userList userMapper.selectAll(); // 3. 封装分页结果可选推荐使用PageInfo PageInfoUser pageInfo new PageInfo(userList);2. PageInfo 核心属性分页结果封装属性说明pageNum当前页码pageSize每页条数total总记录数pages总页数list当前页数据列表prePage上一页页码nextPage下一页页码isFirstPage是否为首页isLastPage是否为末页System.out.println(总记录数 pageInfo.getTotal()); // 100 System.out.println(总页数 pageInfo.getPages()); // 10 System.out.println(当前页数据 pageInfo.getList()); // 10条数据二、高级用法1. 方法参数传递分页参数开启support-methods-arguments: true后可直接通过方法参数传递分页参数// Mapper接口 ListUser selectByPage( Param(name) String name, Param(pageNum) int pageNum, // 分页参数 Param(pageSize) int pageSize // 分页参数 ); // Service层无需调用PageHelper.startPage() ListUser userList userMapper.selectByPage(张三, 1, 10);2. 排序功能// 方式1startPage时指定排序 PageHelper.startPage(1, 10, id DESC); // 方式2使用PageHelper.orderBy()单独指定排序 PageHelper.orderBy(create_time DESC, id ASC); ListUser userList userMapper.selectAll();3. 分页合理化reasonable: true自动修正非法页码页码 0 → 自动查询第 1 页页码 总页数 → 自动查询最后一页4. 自定义分页参数PageObject page PageHelper.startPage(1, 10); page.setOrderBy(id DESC); // 设置排序 page.setReasonable(true); // 临时启用分页合理化三、实现原理核心机制ThreadLocal 存储分页参数PageHelper.startPage()将分页参数存入当前线程的 ThreadLocal 中拦截 MyBatis 查询通过实现 MyBatis 的Interceptor接口拦截 Executor 的query()方法动态修改 SQL分析原始 SQL生成COUNT 语句统计总记录数根据数据库方言添加分页语法如 MySQL 的 LIMIT、Oracle 的 ROW_NUMBER ()执行分页查询先执行 COUNT 获取总记录数再执行分页查询获取当前页数据清理 ThreadLocal查询完成后清除 ThreadLocal 中的分页参数避免线程污染四、避坑指南必看1. 核心限制❌不支持嵌套查询和带有 for update 的 SQL官方明确❌ 分页只对紧跟在 startPage 后的第一条查询语句生效❌ 不要在分页查询后立即执行其他查询可能被错误分页2. 常见问题与解决方案表格问题原因解决方案分页无效1. startPage 调用在查询之后2. 多线程环境下 ThreadLocal 失效1. 确保 startPage 在查询前调用2. 每个线程单独调用 startPage总记录数为 0COUNT 语句执行失败检查 SQL 语法避免复杂子查询影响 COUNT 生成排序失效未指定排序字段或排序语法错误明确指定 ORDER BY确保字段存在3. 性能优化建议分页查询必须指定 ORDER BY使用索引字段避免翻页时数据重复 / 丢失大数据量场景百万级 推荐使用游标分页或基于主键的锚点分页id lastId避免 OFFSET 过大导致性能下降复杂查询先分页查询主键 ID再通过 ID 查询详细数据避免复杂 SQL 影响分页性能五、总结PageHelper是 Java 后端开发尤其是 Spring Boot MyBatis的必备工具核心优势零侵入无需修改原始 SQL直接使用高性能物理分页只查询当前页数据易集成Spring Boot starter 一键集成功能强支持分页合理化、排序、参数传递等高级特性最佳实践项目中统一使用PageHelper.startPage()PageInfo组合配置文件中开启reasonable: true和support-methods-arguments: true分页查询必须指定稳定的 ORDER BY如主键 ID避免在分页查询中使用嵌套查询和 for update

更多文章