MyBatis 分页插件PageHelper

PageHelper 详解

一、PageHelper 是什么?

PageHelper 是一个 MyBatis 的物理分页插件,它通过拦截 MyBatis 的 SQL 执行过程,自动为 SQL 添加分页语句,让开发者无需手动编写分页 SQL。

主要作用:

  1. 自动分页 - 拦截查询 SQL,自动添加分页语句
  2. 简化代码 - 减少重复的分页逻辑编写
  3. 统一管理 - 提供统一的分页数据返回格式
  4. 多数据库支持 - 自动适配不同数据库的分页语法

二、快速使用示例

基础使用:

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+分页
学习成本 中等
灵活性 中等

九、最佳实践建议

  1. 服务层封装
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;
    }
}
  1. 统一返回格式
java 复制代码
@Data
public class PageResult<T> {
    private List<T> data;
    private long total;
    private int pageNum;
    private int pageSize;
    private int pages;
}
  1. 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() 调用即可实现复杂的分页功能。使用时注意:

  1. 确保 startPage() 紧邻查询语句
  2. 合理配置数据库方言
  3. 根据需求选择合适的返回类型(PageInfo 或 Page)
  4. 对于复杂查询考虑自定义 count 语句

熟练掌握 PageHelper 可以极大提升开发效率和代码可维护性。

相关推荐
用户298698530141 分钟前
.NET 文档自动化:Spire.Doc 设置奇偶页页眉/页脚的最佳实践
后端·c#·.net
序安InToo32 分钟前
第6课|注释与代码风格
后端·操作系统·嵌入式
xyy12333 分钟前
C#: Newtonsoft.Json 到 System.Text.Json 迁移避坑指南
后端
洋洋技术笔记35 分钟前
Spring Boot Web MVC配置详解
spring boot·后端
JxWang0536 分钟前
VS Code 配置 Markdown 环境
后端
navms39 分钟前
搞懂线程池,先把 Worker 机制啃明白
后端
JxWang0539 分钟前
离线数仓的优化及重构
后端
Nyarlathotep011340 分钟前
gin01:初探gin的启动
后端·go
JxWang0540 分钟前
安卓手机配置通用多屏协同及自动化脚本
后端
JxWang0542 分钟前
Windows Terminal 配置 oh-my-posh
后端