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

相关推荐
mldong5 小时前
C# 开发者也有自己的轻量工作流引擎了:NuGet 装包,5 分钟跑通一条审批流
后端·c#·.net
爱学堂IT分享7 小时前
鹤翔老师pmp项目管理培训认证考试课 (直播录播题库送学时证明)【共58课时】-51CTO学堂
后端
王的宝库7 小时前
Go 项目结构:从单文件到标准工程布局
开发语言·后端·golang
码事漫谈8 小时前
类型即世界:一个 C++ 程序员的本体论入门
后端
Rain的Java大神之路8 小时前
JavaWeb开发如何解决跨域问题
java·前端·后端·nginx·web安全·面试·运维开发
IT_陈寒10 小时前
Python的多线程居然是个假把式?搞清GIL让我少熬三天夜
前端·人工智能·后端
明月_清风10 小时前
位图与布隆过滤器:海量数据下的"存在性判断"艺术
前端·后端·算法
明月_清风11 小时前
Hash 表从入门到精通:Go 实战与工程细节
前端·后端·算法
考虑考虑11 小时前
ElasticSearch索引命令
运维·后端·elasticsearch
玉宇夕落12 小时前
背单词项目一:融会贯通:从零构建"单词大师"后台——Next.js + Supabase + Drizzle 全栈开发实战
后端