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 小时前
SpringBoot对接大模型开发AI命理测算系统:八字排盘与AI解析接口源码全解
人工智能·spring boot·后端
张不才1 小时前
一个静默吞数据的时间戳陷阱
后端
李少兄2 小时前
从原理到实战:Spring IoC/DI 核心知识体系与高频面试题全解
java·后端·spring
ServBay2 小时前
ServBay 1.30.0 更新:双平台引入 MCP 服务,AI 编程助手成为全栈本地运维
后端·ai编程
张不才2 小时前
分页查出来的数据总少几条?可能是 MyBatis 后置过滤的坑
后端
Windeal2 小时前
Agent ToolCall 循环怎么定制?PI Extension 与 DeepAgents Middleware 两条岔路深度对比
后端·openai
鱼人2 小时前
targets 包实战:R 语言数据分析流水线自动化管理方案
后端
时雨__2 小时前
一文搞懂 Python 并发:GIL、多线程/多进程/协程怎么选
后端
Anson4322 小时前
Dubbo架构深度分析
后端