PageHelper
是一个优秀的 MyBatis 分页插件,它通过简单的拦截器机制,实现了对 MyBatis 查询的物理分页(而非内存分页),极大简化了分页代码的编写。而 PageHelper 扩展 通常指的是在其核心功能基础上,为特定框架(如 Spring Boot)或特定需求(如简化配置、增强功能)提供的增强模块或使用方式。
以下是对 PageHelper
及其常见扩展的介绍:
一、核心 PageHelper 功能回顾
- 核心原理:
- 基于 MyBatis 的
Interceptor
接口,拦截 Executor 的查询方法。 - 在执行目标 SQL 前,自动分析原 SQL 并生成
COUNT
查询(获取总数)和添加了物理分页(如LIMIT
,ROWNUM
)的查询。
- 基于 MyBatis 的
- 基本用法:
// 在查询方法前调用,设置分页参数 PageHelper.startPage(pageNum, pageSize); // pageNum: 页码, pageSize: 每页条数 // 紧接着的第一个 MyBatis 查询方法会被分页 List<Country> list = countryMapper.selectAll(); // 用 PageInfo 包装结果,包含分页详细信息(总记录数、总页数、当前页等) PageInfo<Country> pageInfo = new PageInfo<>(list);
- 主要优点:
- 简单:一行代码启动分页。
- 高效:物理分页,数据库压力小。
- 通用:支持多种数据库(MySQL, Oracle, PostgreSQL, SQLServer 等)。
- 灵活:支持多种参数传递方式(
startPage
方法、RowBounds
参数)。 - 丰富信息:
PageInfo
对象提供全面的分页信息。
二、重要的 PageHelper 扩展
-
pagehelper-spring-boot-starter
- 定位:官方提供的 Spring Boot 自动配置 Starter。
- 核心价值:
- 零配置/简化配置:只需引入依赖,大部分情况下无需任何额外配置即可使用。
- 自动注入:自动配置
PageHelper
拦截器并将其注册到 MyBatisSqlSessionFactory
中。 - 约定优于配置:遵循 Spring Boot 的配置习惯,可以通过
application.properties
/application.yml
轻松配置插件属性。
- 依赖 (Maven):
<dependency><groupId>com.github.pagehelper</groupId><artifactId>pagehelper-spring-boot-starter</artifactId><version>最新版本</version> <!-- 请替换为当前最新版本,如 2.1.0 --> </dependency>
- 常用配置示例 (
application.yml
):pagehelper:helper-dialect: mysql # 指定数据库方言(通常可自动检测)reasonable: true # 启用合理化:pageNum<=0 时设为 1,pageNum>总页数时设为最后一页support-methods-arguments: true # 支持通过 Mapper 接口参数传递分页参数params: count=countSql # 配置 COUNT 查询的返回值 keypage-size-zero: true # 允许 pageSize=0 时查询所有结果(返回 PageInfo,total=实际条数)
- 使用:在 Spring Boot 项目中引入该 starter 后,直接在 Service 或 Controller 中使用
PageHelper.startPage(pageNum, pageSize)
即可。
-
PageHelper
的参数模式扩展- 核心功能扩展:除了
PageHelper.startPage
,PageHelper
本身支持更灵活的参数传递:- 方法参数传递 (需配置
support-methods-arguments: true
):// Mapper 接口 List<User> selectUsers(@Param("name") String name, @Param("pageNum") int pageNum, @Param("pageSize") int pageSize);
// Service 调用 (无需显式调用 startPage) List<User> users = userMapper.selectUsers("John", 2, 10); PageInfo<User> pageInfo = new PageInfo<>(users);
RowBounds
参数传递 (较旧方式,优先级低于startPage
):List<User> users = sqlSession.selectList("selectUsers", null, new RowBounds(2, 10));
- 方法参数传递 (需配置
- 核心功能扩展:除了
-
PageInfo
的增强- 虽然
PageInfo
本身是核心的一部分,但它提供的丰富分页信息是其强大扩展性的体现:getTotal()
:总记录数。getPages()
:总页数。getPageNum()
:当前页码。getPageSize()
:每页条数。getList()
:当前页的数据列表。isIsFirstPage()
/isIsLastPage()
:是否第一页/最后一页。hasPreviousPage()
/hasNextPage()
:是否有上一页/下一页。getPrePage()
/getNextPage()
:上一页/下一页页码。getNavigatepageNums()
:所有导航页码(如 [1,2,3,4,5])。
- 这极大地简化了将分页信息返回给前端的工作。
- 虽然
三、使用 PageHelper 扩展的注意事项
PageHelper.startPage
的调用位置:- 必须紧挨着需要分页的 MyBatis 查询方法调用之前。中间不能有其它可能触发查询的操作(如调用另一个查询方法)。
- 线程安全:
PageHelper.startPage
内部使用ThreadLocal
保存分页参数。这意味着它是线程安全的,但也意味着分页参数只对当前线程的紧接着的下一次查询有效。查询完成后,ThreadLocal
会被自动清理。在异步、多线程或复杂调用链中要特别注意调用时机。
PageInfo
的构造:- 传入
PageInfo
构造器的List
对象,必须是PageHelper.startPage
后执行分页查询返回的那个List
。这个List
实际上是一个Page
对象(实现了List
接口),包含了分页信息。如果用其他List
构造PageInfo
,信息会错误。
- 传入
- 数据库方言 (
dialect
):- 确保配置正确的数据库方言,或让插件自动检测(通常可行)。错误的方言会导致生成错误的分页 SQL。
reasonable
参数:- 建议开启 (
reasonable: true
),避免用户传入非法页码导致空数据或错误。
- 建议开启 (
page-size-zero
:- 如果业务有“pageSize=0 时返回所有数据”的需求,配置
page-size-zero: true
。注意此时PageInfo
的total
是实际数据条数(可能很大),pages
为 1。
- 如果业务有“pageSize=0 时返回所有数据”的需求,配置
- 避免与
RowBounds
混用:- 如果同时使用了
PageHelper.startPage
和RowBounds
参数,PageHelper.startPage
的优先级更高。
- 如果同时使用了
四、总结
- 核心
PageHelper
:提供了 MyBatis 物理分页的核心拦截能力和基础 API (startPage
,PageInfo
)。 - 关键扩展
pagehelper-spring-boot-starter
:极大简化了在 Spring Boot 项目中的集成和使用,是当前最推荐的使用方式,实现了开箱即用。 - 参数模式扩展:提供
startPage
之外更灵活的传参方式(方法参数、RowBounds
),适应不同编码风格。 PageInfo
对象:作为核心功能的一部分,提供了强大的分页信息封装能力,是返回给前端的理想数据结构。
选择建议:对于 Spring Boot 项目,直接使用 pagehelper-spring-boot-starter
是最佳实践。充分利用其自动配置和属性配置,结合 PageHelper.startPage
和 PageInfo
,可以非常高效、简洁地实现功能强大且信息完整的分页功能。理解核心原理和注意事项(尤其是 startPage
的调用位置和线程特性)是避免踩坑的关键。
如果你有特定的 PageHelper 扩展需求(比如集成到其他框架,或者自定义分页逻辑),可以进一步探讨其 SPI 机制或自定义拦截器实现。