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 可以极大提升开发效率和代码可维护性。

相关推荐
Paladin_z2 小时前
Easy Query中间件的使用
后端
牛奔2 小时前
Go语言中结构体转Map优雅实现
开发语言·后端·macos·golang·xcode
掘金码甲哥2 小时前
我不允许谁还分不清这三种watch机制的区别
后端
张心独酌2 小时前
Rust新手练习案例库- rust-learning-example
开发语言·后端·rust
码事漫谈3 小时前
一文读懂“本体论”这个时髦词
后端
IguoChan3 小时前
D2L(2) — softmax回归
后端
码事漫谈3 小时前
C++线程编程模型演进:从Pthread到jthread的技术革命
后端
半夏知半秋3 小时前
kcp学习-skynet中的kcp绑定
开发语言·笔记·后端·学习
szm02254 小时前
Spring
java·后端·spring