当前位置: 首页 > news >正文

[特殊字符] 深入理解 PageHelper 分页原理:从 startPage 到 SQL 改写全过程

在日常开发中,分页几乎是后端系统中最常见的功能之一。
我们在使用 MyBatis + PageHelper 时,只需要一句:

PageHelper.startPage(pageNum, pageSize);
List<User> list = userMapper.selectUserList();

就能实现分页查询。
看似简单,但你是否想过:PageHelper 是如何知道要分页的?
SQL 中的 LIMIT 是在哪里拼接的?
今天我们就来深入分析一下 PageHelper 的工作原理。


🧩 一、分页从哪开始?—— startPage()

分页逻辑的入口就在:

PageHelper.startPage(pageNum, pageSize);

来看它的源码(简化版):

public static <E> Page<E> startPage(int pageNum, int pageSize, boolean count, Boolean reasonable, Boolean pageSizeZero) {Page<E> page = new Page(pageNum, pageSize, count);page.setReasonable(reasonable);page.setPageSizeZero(pageSizeZero);Page<E> oldPage = getLocalPage();if (oldPage != null && oldPage.isOrderByOnly()) {page.setOrderBy(oldPage.getOrderBy());}setLocalPage(page);return page;
}

这段代码其实做了三件事:

  1. 创建一个 Page 对象,保存分页参数(页码、每页数量、是否统计总数等);
  2. 检查旧的 Page 是否存在(如果只设置了排序规则,就继承它);
  3. 把当前 Page 对象存入 ThreadLocal 中

🧠 二、ThreadLocal:分页的关键所在

分页之所以能“自动生效”,关键在于 PageHelper 使用了 ThreadLocal

每个线程都会维护一个自己的分页上下文对象(Page),
这意味着每次请求(通常一个 HTTP 请求对应一个线程)都可以拥有独立的分页参数,不会互相干扰。

简而言之:

startPage() 只是把分页参数存到了当前线程中。

当我们执行 userMapper.selectUserList() 时,
MyBatis 拦截器 会从 ThreadLocal 中取出这个 Page 对象,
在 SQL 执行前,自动为 SQL 拼接上分页语句。


🧩 三、拦截器如何改写 SQL?

PageHelper 注册了一个 MyBatis 拦截器:

@Intercepts({@Signature(type = StatementHandler.class,method = "prepare",args = {Connection.class, Integer.class}
)})

每当 MyBatis 准备执行 SQL 时,这个拦截器会被触发。
它会:

  1. 判断当前线程是否存在 Page(也就是我们在 startPage() 放进去的);
  2. 如果存在,就改写 SQL,拼上分页语句;
  3. 执行一次 count 查询,用于获取总记录数;
  4. 最终返回结果列表 + 分页信息。

例如,原 SQL:

SELECT * FROM sys_user WHERE status = 1;

经过 PageHelper 改写后变为:

SELECT * FROM sys_user WHERE status = 1 LIMIT 0, 10;

同时还会额外执行:

SELECT COUNT(1) FROM sys_user WHERE status = 1;

🧩 四、分页结果是怎么返回的?

分页查询返回后,我们一般会调用:

return getDataTable(list);

而若依框架中的 getDataTable() 方法是这样写的:

protected TableDataInfo getDataTable(List<?> list)
{TableDataInfo rspData = new TableDataInfo();rspData.setCode(HttpStatus.SUCCESS);rspData.setRows(list);rspData.setTotal(new PageInfo(list).getTotal());return rspData;
}

其中 PageInfo 内部会读取 PageHelper 存在 ThreadLocal 中的分页信息,
包括:

  • 总记录数 total
  • 当前页码 pageNum
  • 每页数量 pageSize
  • 总页数 pages

最终生成 JSON 响应:

{"code": 200,"rows": [ ...用户数据... ],"total": 153
}

⚙️ 五、参数说明与高级特性

PageHelper 的分页控制非常灵活,它的 startPage() 还有以下参数:

参数名含义
pageNum当前页码
pageSize每页数量
count是否统计总记录数
reasonable是否启用页码合理化(超出范围时自动调整)
pageSizeZero是否允许 pageSize=0 返回所有记录

例如:

PageHelper.startPage(1, 0, true, true, true);

→ 代表:第一页,不分页(返回全部数据),执行 count 查询。


🧩 六、为什么要用 ThreadLocal?

使用 ThreadLocal 的核心目的,是为了在 不修改原 SQL 的情况下实现分页。
因为 MyBatis 执行 SQL 的过程是多层封装的,
分页插件无法直接知道当前的分页参数。

因此 PageHelper 采用 ThreadLocal 方案:

  • Controller 调用 startPage() 时,将分页信息保存到线程上下文;
  • MyBatis 拦截器在执行 SQL 前,从线程中读取分页参数;
  • 执行结束后自动清理 ThreadLocal,防止污染其他线程。

💣 七、常见问题:分页内存泄漏?

由于 PageHelper 使用了 ThreadLocal,如果使用不当,也可能造成内存泄漏。
例如线程池复用时,如果分页对象没有清理干净,旧的分页参数可能残留。

解决方法:
PageHelper 内部已在 finally 块中清理 ThreadLocal;
如果是自定义 ThreadLocal,请务必在使用后调用:

threadLocal.remove();

✅ 八、总结

步骤说明
startPage()在当前线程中创建分页上下文(Page对象)
MyBatis 拦截器在执行 SQL 前读取 Page 信息并改写 SQL
count 查询自动统计总记录数
PageInfo封装分页结果
ThreadLocal实现线程级隔离,保证分页参数安全传递

一句话总结:

PageHelper 通过 ThreadLocal + MyBatis 拦截器 实现了“无侵入式分页”。
开发者无需在 SQL 中写 LIMIT,就能优雅地实现数据库层分页。


💬 九、写在最后

分页是每个后端工程师都会接触的功能,但理解它的底层原理,
不仅能帮助我们更好地使用 PageHelper,也能在设计自己的分页组件时少走弯路。

下次你再写:

startPage();
List<User> list = userMapper.selectUserList();

就能清楚知道:这不仅仅是分页,而是一套完整的 线程上下文 + SQL 拦截体系 在默默为你工作。


http://www.dtcms.com/a/479665.html

相关文章:

  • 唐山cms模板建站紫色网站
  • 岳阳做网站多少钱产品推广软文300字
  • 青岛建站方案网络营销存在的问题及解决对策
  • 备案编号不放在网站广州公司宣传片设计
  • 自己建网站做外贸湖南搜索引擎推广服务
  • 网站建设心得总结素材解析网站搭建
  • Git 换行符(LF/CRLF)警告:原因与跨平台配置解决方案
  • 烟台公司网站定制个人怎么进行网络广告营销
  • 做黑彩网站赚钱吗项目外包公司到底值不值得去
  • 网站收录网深圳市住房和建设局官方网站
  • 全国重点射击学校锦标赛
  • 学习MySQL数据库的高级特性(上)
  • 卫计局网站建设信息公开总结陕西网络推广维护
  • 惠州网站制作公司找工程项目
  • 【CTF夺旗赛】文件包含漏洞攻防
  • 网站建设和使用现状网站 多个ip 备案
  • 网站的域名和空间外贸建站及推广
  • 中国平安官方网站心态建设课件广州软件开发公司排行榜
  • xps13适合网站开发吗wordpress tagline
  • 手机做兼职的网站公司取名网免费版
  • 推荐的 Visual Studio 2026 Insider C++ 程序项目属性配置
  • 【C学习】13-数组使用与运算
  • 甜品网站首页设计昆明市住房和城乡建设局网站上看的
  • 越秀公司网站建设洛阳霞光科技专业网站制作
  • 做外贸的都有那些网站百度seo是什么意思呢
  • 网站制作的语言云建站网址
  • 网站开发试验报告上海外贸大厦
  • JAVA实现调整字符串
  • SSM教务信息管理系统3rtdg(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。
  • JAVA同城服务上门家政派单系统源码,安装部署指南、API接口文档、二次开发手册