在苍穹外卖项目中,用PageHelper实现了对员工的分页查询。来看看PageHelper是如何与Mybatis协作的!
协作时序图如下
sequenceDiagram
participant Frontend as 前端
participant Service as Service层
participant PageHelper as PageHelper
participant Mapper as Mapper
participant Interceptor as MyBatis拦截器
participant DB as 数据库
Frontend->>Service: GET /admin/employee/page<br/>page=1, pageSize=10
Service->>PageHelper: startPage(1, 10)
Note over PageHelper: ThreadLocal存储分页参数
Service->>Mapper: pageQuery(EmployeePageQueryDTO)
Mapper->>Interceptor: 执行查询
Note over Mapper,Interceptor: 原始SQL:<br/>SELECT * FROM employee<br/>ORDER BY create_time DESC
Interceptor->>PageHelper: 拦截SQL请求
PageHelper->>Interceptor: 改写SQL + 添加LIMIT
Note over PageHelper: SQL转换:<br/>原始 → SELECT * FROM employee ...<br/>改写 → SELECT * FROM employee ... LIMIT 0,10
Interceptor->>DB: 执行COUNT查询
Note over Interceptor,DB: 自动生成COUNT SQL:<br/>SELECT COUNT(*) FROM employee
DB-->>Interceptor: 返回总数: 100
Interceptor->>DB: 执行分页查询
Note over Interceptor,DB: 执行分页SQL:<br/>SELECT * FROM employee<br/>ORDER BY create_time DESC<br/>LIMIT 0,10
DB-->>Interceptor: 返回10条员工数据
Interceptor->>Mapper: 返回Page<Employee>对象
Note over Interceptor,Mapper: Page对象包含:<br/>- 数据列表(10条)<br/>- 总数(100)<br/>- 分页信息
Mapper-->>Service: Page<Employee>
Service->>Service: 构建PageResult
Note over Service: PageResult:<br/>total=100, records=[...]
Service-->>Frontend: Result<PageResult>
Note over PageHelper: 自动清理ThreadLocal分页参数
引言:分页就像翻书
想象一下,你有一本1000页的员工花名册,每次查看时,你不需要一次性翻阅所有页面,而是根据目录找到对应的页码,每次只查看10-20页。这就是分页的核心思想——按需加载,提升效率。
在Spring Boot + MyBatis项目中,实现分页查询往往需要手动编写复杂的SQL语句,计算偏移量,处理总数统计。而PageHelper的出现,让这一切变得异常简单。
一、问题背景:传统分页的痛点
在sky-take-out项目的员工管理模块中,我们需要实现员工列表的分页查询。传统做法需要:
-- 需要手动计算偏移量
SELECT * FROM employee
ORDER BY create_time DESC
LIMIT 0, 10; -- 第1页
SELECT * FROM employee
ORDER BY create_time DESC
LIMIT 10, 10; -- 第2页
还需要单独执行COUNT查询获取总数:
SELECT COUNT(*) FROM employee;
这种模式不仅代码冗余,而且容易出错。
二、PageHelper:分页的"智能管家"
2.1 核心原理
PageHelper是一个MyBatis分页插件,它通过拦截器机制在运行时自动处理分页逻辑:
- 设置分页参数:
PageHelper.startPage(pageNum, pageSize) - 拦截SQL:自动在查询前拦截
- 改写SQL:添加LIMIT子句
- 执行COUNT:自动生成并执行COUNT查询
- 返回Page对象:包含数据列表和分页信息
2.2 在员工查询中的应用
让我们看看sky-take-out项目中如何优雅地使用PageHelper:
步骤1:Service层设置分页
@Override
public PageResult pageQuery(EmployeePageQueryDTO employeePageQueryDTO) {
// 关键一行:设置分页参数
PageHelper.startPage(employeePageQueryDTO.getPage(), employeePageQueryDTO.getPageSize());
// 正常执行Mapper查询
Page<Employee> page = employeeMapper.pageQuery(employeePageQueryDTO);
// 返回封装好的分页结果
return new PageResult(page.getTotal(), page.getResult());
}
步骤2:Mapper层定义接口
/**
* 分页查询员工
* @param employeePageQueryDTO
*/
Page<Employee> pageQuery(EmployeePageQueryDTO employeePageQueryDTO);
步骤3:XML中编写业务SQL
<select id="pageQuery" parameterType="EmployeePageQueryDTO" resultType="com.sky.entity.Employee">
SELECT * FROM employee
<where>
<if test="name != null and name != ''">
AND name like concat('%', #{name}, '%')
</if>
</where>
ORDER BY create_time DESC
</select>
注意:这里完全不需要关心分页逻辑,只需编写业务查询!
三、PageHelper的魔法时刻
3.1 自动SQL改写
当你调用employeeMapper.pageQuery()时,PageHelper在幕后执行了以下魔法:
原始SQL: SELECT * FROM employee ORDER BY create_time DESC
改写后: SELECT * FROM employee ORDER BY create_time DESC LIMIT 0, 10
从日志中可以看到实际效果:
2026-04-26 00:03:12.142 DEBUG: ==> Preparing:
SELECT * FROM employee ORDER BY create_time DESC LIMIT ?
2026-04-26 00:03:12.142 DEBUG: ==> Parameters: 10(Integer)
3.2 智能COUNT查询
PageHelper会自动执行COUNT查询获取总记录数,无需开发者手动编写:
SELECT COUNT(*) FROM employee
3.3 返回完整的Page对象
查询结果被封装在Page<Employee>对象中,包含:
page.getResult(): 当前页的员工列表page.getTotal(): 总员工数page.getPageNum(): 当前页码page.getPageSize(): 每页大小page.getPages(): 总页数
四、最佳实践建议
4.1 配置建议
在application.yml中配置PageHelper:
pagehelper:
helper-dialect: mysql
reasonable: true
support-methods-arguments: true
4.2 使用规范
- 紧邻查询调用:
PageHelper.startPage()应紧邻Mapper调用 - 异常处理:确保在finally块或AOP中清理ThreadLocal
- 参数验证:验证page和pageSize的合法性
4.3 避坑
// ❌ 错误:分页设置后执行了其他查询
PageHelper.startPage(1, 10);
someOtherMapper.query(); // 这会受到影响!
employeeMapper.pageQuery();
// ✅ 正确:分页设置后立即执行目标查询
PageHelper.startPage(1, 10);
employeeMapper.pageQuery();
五、总结
PageHelper的出现,让MyBatis分页从"体力活"变成了"智能活"。它就像一位贴心的助手,在你需要分页时默默处理好一切,让你可以专注于业务逻辑的实现。
在sky-take-out项目中,正是PageHelper的加持,让员工分页查询变得如此简洁优雅。下次当你需要实现分页时,不妨试试PageHelper,体验一下"一行代码搞定分页"的快感!
参考
苍穹外卖www.bilibili.com/video/BV1TP…
deekseek-v4