PageHelper 详解
一、PageHelper 是什么?
PageHelper 是一个 MyBatis 的物理分页插件,它通过拦截 MyBatis 的 SQL 执行过程,自动为 SQL 添加分页语句,让开发者无需手动编写分页 SQL。
主要作用:
- 自动分页 - 拦截查询 SQL,自动添加分页语句
- 简化代码 - 减少重复的分页逻辑编写
- 统一管理 - 提供统一的分页数据返回格式
- 多数据库支持 - 自动适配不同数据库的分页语法
二、快速使用示例
基础使用:
java
// 1. 设置分页参数(第2页,每页10条)
PageHelper.startPage(2, 10);
// 2. 执行查询(会自动分页)
List<User> userList = userMapper.selectAll();
// 3. 获取分页信息
PageInfo<User> pageInfo = new PageInfo<>(userList);
// 使用分页数据
System.out.println("当前页:" + pageInfo.getPageNum()); // 2
System.out.println("每页条数:" + pageInfo.getPageSize()); // 10
System.out.println("总记录数:" + pageInfo.getTotal()); // 总数据量
System.out.println("总页数:" + pageInfo.getPages()); // 总页数
System.out.println("当前页数据:" + pageInfo.getList()); // 当前页的数据
三、完整配置指南
1. Maven 依赖
xml
<!-- Spring Boot 项目 -->
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-boot-starter</artifactId>
<version>1.4.6</version>
</dependency>
<!-- 非 Spring Boot 项目 -->
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>5.3.2</version>
</dependency>
2. Spring Boot 配置(application.yml)
yaml
pagehelper:
# 数据库方言(自动检测可设为 auto)
helper-dialect: mysql
# 分页合理化:pageNum<=0 查询第一页,pageNum>总页数查询最后一页
reasonable: true
# 支持通过 Mapper 接口参数传递分页参数
support-methods-arguments: true
# 默认值为 false,设为 true 时,RowBounds 第一个参数 offset 当成 pageNum 使用
offset-as-page-num: true
# 分页参数合理化
page-size-zero: false
# 默认为 false,设为 true 允许 pageSize=0 查询全部结果
params: count=countSql
四、多种使用方式
方式1:基本分页查询
java
public PageInfo<User> findUsers(int pageNum, int pageSize) {
// 开始分页
PageHelper.startPage(pageNum, pageSize);
// 查询数据(自动分页)
List<User> list = userMapper.selectByExample(null);
// 包装分页结果
return new PageInfo<>(list);
}
方式2:带条件的分页查询
java
public PageInfo<User> findUsersByCondition(UserQuery query, int pageNum, int pageSize) {
PageHelper.startPage(pageNum, pageSize);
Example example = new Example(User.class);
if (StringUtils.isNotBlank(query.getName())) {
example.createCriteria().andLike("name", "%" + query.getName() + "%");
}
List<User> list = userMapper.selectByExample(example);
return new PageInfo<>(list);
}
方式3:返回 Page 对象
java
public Page<User> findUsersPage(int pageNum, int pageSize) {
PageHelper.startPage(pageNum, pageSize);
// Page 是 ArrayList 的子类,自带分页信息
Page<User> page = (Page<User>) userMapper.selectAll();
// 可以直接获取分页信息
System.out.println("总数:" + page.getTotal());
return page;
}
方式4:使用 RowBounds(不推荐)
java
// 不侵入代码的方式
public List<User> findUsersWithRowBounds(int pageNum, int pageSize) {
RowBounds rowBounds = new RowBounds((pageNum-1)*pageSize, pageSize);
return userMapper.selectByRowBounds(null, rowBounds);
}
五、PageInfo 常用属性
| 属性 | 说明 | 示例 |
|---|---|---|
getList() |
当前页数据列表 | List<T> |
getTotal() |
总记录数 | 100 |
getPages() |
总页数 | 10 |
getPageNum() |
当前页码 | 1 |
getPageSize() |
每页数量 | 10 |
isFirstPage() |
是否第一页 | true |
isLastPage() |
是否最后一页 | false |
isHasNextPage() |
是否有下一页 | true |
isHasPreviousPage() |
是否有上一页 | false |
getNavigatePages() |
导航页码数 | 8 |
getNavigatepageNums() |
导航页码数组 | [1,2,3,4,5,6,7,8] |
六、进阶用法
1. 排序功能
java
// 方式1:使用参数排序
PageHelper.startPage(1, 10, "create_time desc");
// 方式2:使用 OrderBy 方法
PageHelper.startPage(1, 10)
.setOrderBy("age asc, name desc");
List<User> list = userMapper.selectAll();
2. 只统计数量不分页
java
// 只进行 count 查询
PageHelper.startPage(1, 0); // pageSize=0 时只查询总数
long total = ((Page<?>) userMapper.selectAll()).getTotal();
3. 分页拦截器设置参数
java
// 可以在代码中动态设置参数
PageHelper.startPage(1, 10)
.setCount(true) // 是否进行 count 查询
.setReasonable(false) // 关闭合理化
.setPageSizeZero(true); // 允许 pageSize=0
七、常见问题解决方案
问题1:分页不生效
java
// ❌ 错误写法:中间有其他查询
PageHelper.startPage(1, 10);
userMapper.countAll(); // 这个查询会被分页
List<User> list = userMapper.selectAll(); // 这个不会分页
// ✅ 正确写法:紧邻查询语句
PageHelper.startPage(1, 10);
List<User> list = userMapper.selectAll(); // 这个会分页
问题2:自定义 count 查询
xml
<!-- 在 Mapper.xml 中定义 count 查询 -->
<select id="selectComplexCount" resultType="long">
SELECT COUNT(*) FROM user WHERE status = 1
</select>
java
// 使用自定义 count 查询
PageHelper.startPage(1, 10)
.setCountId("selectComplexCount");
问题3:多表关联查询分页
java
// 对于复杂查询,可以在 SQL 中使用 PageHelper
PageHelper.startPage(1, 10);
// 自己写 JOIN 查询的 SQL
List<UserDTO> list = userMapper.selectUserWithRole();
八、与 MyBatis-Plus 对比
| 特性 | PageHelper | MyBatis-Plus |
|---|---|---|
| 侵入性 | 无侵入 | 需要继承 BaseMapper |
| 使用方式 | ThreadLocal | 传入 Page 对象 |
| 功能范围 | 专注分页 | 全套 CRUD+分页 |
| 学习成本 | 低 | 中等 |
| 灵活性 | 高 | 中等 |
九、最佳实践建议
- 服务层封装
java
public class PageUtils {
public static <T> PageResult<T> toPageResult(PageInfo<T> pageInfo) {
PageResult<T> result = new PageResult<>();
result.setData(pageInfo.getList());
result.setTotal(pageInfo.getTotal());
result.setPageNum(pageInfo.getPageNum());
result.setPageSize(pageInfo.getPageSize());
return result;
}
}
- 统一返回格式
java
@Data
public class PageResult<T> {
private List<T> data;
private long total;
private int pageNum;
private int pageSize;
private int pages;
}
- Controller 使用
java
@GetMapping("/users")
public Result listUsers(@RequestParam(defaultValue = "1") int pageNum,
@RequestParam(defaultValue = "10") int pageSize) {
PageInfo<User> pageInfo = userService.findUsers(pageNum, pageSize);
return Result.success(PageUtils.toPageResult(pageInfo));
}
总结
PageHelper 是一个非常实用的 MyBatis 分页插件,通过简单的 PageHelper.startPage() 调用即可实现复杂的分页功能。使用时注意:
- 确保
startPage()紧邻查询语句 - 合理配置数据库方言
- 根据需求选择合适的返回类型(PageInfo 或 Page)
- 对于复杂查询考虑自定义 count 语句
熟练掌握 PageHelper 可以极大提升开发效率和代码可维护性。