MyBatis 分页插件PageHelper

0 阅读4分钟

PageHelper 详解

一、PageHelper 是什么?

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

主要作用:

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

二、快速使用示例

基础使用:

// 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 依赖

<!-- 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)

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:基本分页查询

public PageInfo<User> findUsers(int pageNum, int pageSize) {
    // 开始分页
    PageHelper.startPage(pageNum, pageSize);
    
    // 查询数据(自动分页)
    List<User> list = userMapper.selectByExample(null);
    
    // 包装分页结果
    return new PageInfo<>(list);
}

方式2:带条件的分页查询

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 对象

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(不推荐)

// 不侵入代码的方式
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. 排序功能

// 方式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. 只统计数量不分页

// 只进行 count 查询
PageHelper.startPage(1, 0);  // pageSize=0 时只查询总数
long total = ((Page<?>) userMapper.selectAll()).getTotal();

3. 分页拦截器设置参数

// 可以在代码中动态设置参数
PageHelper.startPage(1, 10)
    .setCount(true)           // 是否进行 count 查询
    .setReasonable(false)     // 关闭合理化
    .setPageSizeZero(true);   // 允许 pageSize=0

七、常见问题解决方案

问题1:分页不生效

// ❌ 错误写法:中间有其他查询
PageHelper.startPage(1, 10);
userMapper.countAll();  // 这个查询会被分页
List<User> list = userMapper.selectAll();  // 这个不会分页

// ✅ 正确写法:紧邻查询语句
PageHelper.startPage(1, 10);
List<User> list = userMapper.selectAll();  // 这个会分页

问题2:自定义 count 查询

<!-- 在 Mapper.xml 中定义 count 查询 -->
<select id="selectComplexCount" resultType="long">
    SELECT COUNT(*) FROM user WHERE status = 1
</select>
// 使用自定义 count 查询
PageHelper.startPage(1, 10)
    .setCountId("selectComplexCount");

问题3:多表关联查询分页

// 对于复杂查询,可以在 SQL 中使用 PageHelper
PageHelper.startPage(1, 10);
// 自己写 JOIN 查询的 SQL
List<UserDTO> list = userMapper.selectUserWithRole();

八、与 MyBatis-Plus 对比

特性PageHelperMyBatis-Plus
侵入性无侵入需要继承 BaseMapper
使用方式ThreadLocal传入 Page 对象
功能范围专注分页全套 CRUD+分页
学习成本中等
灵活性中等

九、最佳实践建议

  1. 服务层封装
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. 统一返回格式
@Data
public class PageResult<T> {
    private List<T> data;
    private long total;
    private int pageNum;
    private int pageSize;
    private int pages;
}
  1. Controller 使用
@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 可以极大提升开发效率和代码可维护性。