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+ 个属性精简整理,只返回前端常用的

相关推荐
爱勇宝1 天前
第 1 章:别把“需求文档”当成真正的需求
前端·后端·程序员
IT_陈寒1 天前
闭包陷阱让我加了两天班,JavaScript你真行
前端·人工智能·后端
易协同低代码1 天前
通达OA核心类库TD类深度解析
后端
Gopher_HBo1 天前
Go语言学习笔记(十八)Gin处理Session
后端
谭光志1 天前
工具塞满上下文窗口怎么办?深度拆解 AI Agent Tool Search 按需加载实现原理
前端·后端·ai编程
她说..1 天前
Java 默认值设置方式
java·开发语言·后端·springboot
foggyprojects1 天前
从0开始,一句话启动AI DataAgent
后端·数据分析·ai编程
郡杰1 天前
一些基础和问题解决
后端
陈随易1 天前
前端项目部署只要30秒
前端·后端·程序员
YIAN1 天前
从零手写文件读取 MCP 服务:一文吃透 Model Context Protocol 全链路通信原理
前端·后端·mcp