MyBatis分页:PageHelper
📖 前言:为什么需要分页?
在处理大量数据时,一次性从数据库查询并返回所有结果是不可行的,这会带来巨大的性能和内存开销。分页是解决这一问题的标准方案。而PageHelper是一个极其流行的MyBatis物理分页插件,它能以“非侵入式”的方式,让我们无需在SQL中编写LIMIT
子句,即可轻松实现分页。
🎯 什么是PageHelper?
PageHelper是一个MyBatis插件,它通过AOP拦截即将执行的SQL查询。当你发起一个分页请求时,它会自动为你追加对应数据库方言的分页语句(如MySQL的LIMIT
),从而实现物理分页。其最大的优点是你只需编写最纯粹的业务查询SQL,将分页逻辑与业务逻辑完全解耦。
🔧 Spring Boot集成
1. 添加依赖
在pom.xml
中引入官方的starter
依赖:
<dependency><groupId>com.github.pagehelper</groupId><artifactId>pagehelper-spring-boot-starter</artifactId><version>2.1.0</version> </dependency>
2. 关于配置 (application.yml
)
在很多情况下,由于starter
强大的自动检测能力(例如,它可以根据JDBC URL自动识别数据库类型),PageHelper可以零配置工作,但强烈建议进行显式配置。
为什么推荐配置?
- 稳定性:明确指定
helper-dialect
可以避免因JDBC URL不规范导致的方言识别失败。 - 功能开启:可以方便地开启
reasonable
(分页参数合理化)等高级功能。 - 清晰性:配置即文档,让项目配置一目了然。
推荐配置 (application.yml
)
pagehelper:helper-dialect: mysql # 明确指定数据库方言reasonable: true # 开启分页参数合理化
🚀 核心用法:两种主流风格 (Page
vs PageInfo
)
PageHelper的核心魅力在于其简洁的调用方式。主要有两种风格,一种是使用PageInfo
全家桶,另一种是像您展示的那样,使用Page
对象手动封装。
1:使用 PageInfo
(便捷的一站式方案)
这是官方最推荐的用法,它将所有分页信息封装在一个PageInfo
对象中,非常方便。
流程:
PageHelper.startPage(pageNum, pageSize);
List<T> list = yourMapper.select(...);
PageInfo<T> pageInfo = new PageInfo<>(list);
- 将
pageInfo
对象返回给前端。
@Service
public class UserServiceImpl implements UserService {@Autowiredprivate UserMapper userMapper;@Overridepublic PageInfo<User> findUsersByPage(int pageNum, int pageSize) {// 1. 开启分页PageHelper.startPage(pageNum, pageSize);// 2. 执行查询 (这是一个普通的、不带分页的查询)List<User> userList = userMapper.findAll();// 3. 将查询结果封装到PageInfo对象中PageInfo<User> pageInfo = new PageInfo<>(userList);return pageInfo;}
}
核心属性与方法
PageInfo
是PageHelper返回的核心对象,它包含了丰富的分页信息,可以直接序列化为JSON返回给前端。
属性 | 类型 | 说明 |
---|---|---|
pageNum | int | 当前页码 |
pageSize | int | 每页数量 |
size | int | 当前页的数量 |
total | long | 总记录数 |
pages | int | 总页数 |
list | List<T> | 当前页的数据列表 |
prePage | int | 上一页页码 |
nextPage | int | 下一页页码 |
isFirstPage | boolean | 是否为第一页 |
isLastPage | boolean | 是否为最后一页 |
hasPreviousPage | boolean | 是否有上一页 |
hasNextPage | boolean | 是否有下一页 |
优点:PageInfo
对象包含了总页数、总条数、是否有上一页/下一页等所有前端分页组件需要的信息,一步到位。
2:强转为 Page<T>
这种方式同样非常流行,它提供了更高的自定义灵活性。
工作原理:当PageHelper.startPage()
被调用后,PageHelper会确保紧跟其后的MyBatis查询返回的List
对象,其实际类型是com.github.pagehelper.Page
。Page
类继承自ArrayList
,但额外包含了分页信息(如总条数total
)。
// 1. 开启分页
PageHelper.startPage(1, 10);// 2. mapper.list() 表面上返回的是 List<Emp>,
// 但其在运行时的真实类型是 Page<Emp>
List<Emp> empList = empMapper.list();// 3. 因此,可以安全地进行强制类型转换
Page<Emp> page = (Page<Emp>) empList;
使用场景
Page<T>
主要用于需要高度自定义返回格式的场景。开发者通过将其强转后,可以精确地提取出 total
和 list
数据,然后封装进自己项目规定的 PageBean
或 ResultVO
等DTO(数据传输对象)中,完全掌控API的响应结构。
优点:返回给前端的JSON结构完全由您自己定义,可以做到最精简,不受PageInfo
固定结构的限制。
核心属性与方法
Page<T>
对象提供了获取分页所需的最基本、最核心的数据:
方法名 | 返回类型 | 说明 |
---|---|---|
getTotal() | long | 获取总记录数 |
getResult() | List<T> | 获取当前页的数据列表 (等同于对象本身) |
getPages() | int | 获取总页数 |
getPageNum() | int | 获取当前页码 |
getPageSize() | int | 获取每页显示数量 |
getStartRow() | long | 获取当前页的起始行号 (从1开始) |
getEndRow() | long | 获取当前页的结束行号 |