PageHelper分页的原理

PageHelper会通过修改SQL语句的方式,在SQL后面动态拼接上limit语句

流程

ThreadLocal 隔离线程数据

PageHelper 是一个基于 MyBatis 的 拦截器(Interceptor) 实现的分页插件。它的核心原理是在 MyBatis 执行 SQL 之前,动态修改 SQL 语句,加入数据库方言相关的分页语法(比如 MySQL 的 LIMIT)。

PageHelper.startPage() 会将分页参数封装成 Page 对象,存入当前线程的 ThreadLocal

实现线程隔离,多并发请求之间分页参数互不干扰。

MyBatis 拦截器捕获查询请求

PageInterceptor 通过 @Intercepts 注解拦截 Executor 的 query 方法。

Executor 是 MyBatis 的核心执行器接口,定义了所有 SQL 执行方法。

dialect.skip() 内部调用了 PageHelper.getLocalPage(),从 ThreadLocal 取分页参数

总数查询 + 分页数据查询

执行 COUNT 查询

改写 SQL(加 LIMIT)+ 执行分页查询

清理 ThreadLocal

PageHelper.startPage() 必须紧跟 Mapper 查询,拦截器只会在有分页参数的查询执行后 才会清理 ThreadLocal

如果查询没执行,或执行前就异常了,ThreadLocal 不会被清理

存储分页参数->拦截并改造 SQL->封装结果并清理现场

返回数据

ini 复制代码
PageHelper.startPage(1,10)
List<Dept> list=deptMapper.selectDept(name, status);

这里容易产生误区,以为返回的是单纯的Dept对象集合

此时deptMapper.selectDept(name, status)返回的对象为page对象,为list接口的一个实现类

page对象中不仅有Dept数据集合,还有着页码等信息

ini 复制代码
List<User> data = page.getResult();
long total = page.getTotal();

实际项目中,更多的是pageInfo来接收数据:

ini 复制代码
List<Dept> list=deptMapper.selectDept(name, status);
//PageInfo的构造器中将page的结果集合分页属性拆分
PageInfo<Dept> pageInfo=new PageInfo<>(list);
pageResult.setRows(pageInfo.getList());
pageResult.setTotal(pageInfo.getTotal());

一是因为Controller层不应该直接依赖MyBatis持久层

二是Page中有很多前端不需要的属性,直接返回会污染接口。

而PageInfo 把 Page 的 20+ 个属性精简整理,只返回前端常用的

相关推荐
笃行35019 小时前
SQLServer数据迁移之后,那张报表还能不能秒出
后端
LucianaiB19 小时前
别再被 AI 骗了:我把腾讯云 4 个 Skill 做成了个「AI 打假侦探」,过程的一个小配置坑惨了我
后端
candyTong20 小时前
Claude Code 如何恢复一段会话
后端·架构·ai编程
En^_^Joy21 小时前
Django项目配置全攻略:settings配置文件
后端·python·django
IT_陈寒1 天前
Python线程池吞了异常还不告诉我,这谁顶得住啊
前端·人工智能·后端
小强库计算机毕业设计1 天前
SpringBoot+Vue3 学生宿舍管理系统实战
java·spring boot·后端·vue·学生宿舍管理系统
小狼1831 天前
实践6|SDD 实战:AI 写的规格被推翻了四次
后端·claude
篮框坏了1 天前
"DeepSeek Harness 实测:一毛钱干三活,但默认配置是个坑"
后端·ai编程
jobBridge211 天前
大模型到底是怎么"想"的?我把 Transformer 拆开,发现它其实是个"接词狂魔"
人工智能·后端·编程语言
唐青枫1 天前
看懂内存地址之后,才算真正入门 Zig:指针、切片与实战
后端