RuoYi-Vue 分页机制全解析:前端参数传递、后端 PageHelper 实现与 SQL 执行过程
·
目录
一.问题引入:10000 条用户数据怎么显示?
想象一下,你的系统中有 10,000 个用户。如果前端一次性请求全部数据并渲染到页面上,会带来哪些问题?
- 前端内存压力大:浏览器需加载并处理大量 DOM 元素,可能导致卡顿甚至崩溃。
- 网络传输慢:一次性传输大量数据占用带宽,响应时间长。
- 用户体验差:用户需要滚动很久才能找到目标信息。
- 后端资源消耗高:数据库查询全表、应用服务器内存占用激增。
因此,数据分页(Pagination) 成为解决大数据量展示的标准方案。
二.什么是数据分页
数据分页是将大量数据按固定数量拆分成分批(页),按需加载 / 展示的技术,核心是避免一次性处理全部数据。
三.源码分析
3.1前端分析
页面中是如何渲染

前端数据获取

向后端发送请求

3.2后端分析
看前端请求后端的url,和上面的请求后端的url一致

找到并分析后端代码controller层中对应的接口申明'/system/post/list'

这里主要使用startPage和getDataTable(list)实现分页查询
3.2.1startPage


3.2.1.1PageHelper 实现
PageHelper.startPage(pageNum, pageSize, orderBy).setReasonable(reasonable);
- 这是 PageHelper 插件的核心 API,作用是:初始化分页上下文,告诉 MyBatis「接下来的一次 SQL 查询需要分页」。
PageHelper.startPage(...):- 第一个参数
pageNum:当前页码; - 第二个参数
pageSize:每页条数; - 第三个参数
orderBy:排序规则(已做防注入处理),会自动拼接进 SQL 的ORDER BY子句; - 该方法返回一个
Page对象,用于配置额外分页规则(如reasonable)。
- 第一个参数
.setReasonable(reasonable):启用 / 禁用分页合理性校验(对应前面的reasonable参数)。
3.2.1.2PageHelper 工作原理
这段代码执行后,后续执行的 MyBatis Mapper 查询方法 会被 PageHelper 拦截,自动完成 2 件事:
- 对查询 SQL 拼接分页语法(如 MySQL):
- 原 SQL:
SELECT * FROM sys_user WHERE status = 1 - 拦截后 SQL:
SELECT * FROM sys_user WHERE status = 1 ORDER BY create_time DESC LIMIT 0, 10(pageNum=1,pageSize=10 时,LIMIT 起始索引 = 0,条数 = 10);
- 原 SQL:
- 自动查询总条数:PageHelper 会额外执行一条
COUNT(*)语句(如SELECT COUNT(*) FROM sys_user WHERE status = 1),用于计算总数据量total,后续会返回给前端,让前端分页组件计算总页数。

调用时机:
startPage()必须在 MyBatis 查询方法执行前 调用(紧挨着查询方法),否则分页失效。
3.2.2getDataTable(list)

rspData.setTotal(new PageInfo(list).getTotal());是关键步骤:通过 PageInfo 从 list 中提取总数据条数 total。

将 PageHelper 处理后的 (page继承于list) 封装成
PageInfo对象,从PageInfo中获取总数据条数。
Page<E>(分页数据载体)
- 继承自
ArrayList<E>,是 PageHelper 插件中承载当前页数据的核心类。它不仅存储当前页的列表数据(如查询到的 10 条用户信息),还隐藏了分页元数据(如总条数total、当前页码pageNum等)。 - 作用:让分页后的列表可以直接以
List类型返回(多态特性),同时通过PageInfo可提取分页元数据。
四.总结
数据分页过程
- 调用
PageHelper.startPage(pageNum, pageSize)后,插件会在 ThreadLocal 中存储分页参数; - 执行 MyBatis 查询时,插件拦截 SQL,自动拼接
LIMIT并查询总条数; - 查询结果被封装为
Page<E>(继承ArrayList),既包含当前页数据,也隐含总条数等元数据; - 前端通过
PageInfo提取total(总条数),结合Page中的列表数据,实现分页渲染。
五.查看第二页的数据

5.1后端返回的log
21:23:43.754 [http-nio-8080-exec-20] DEBUG c.r.s.m.S.selectOperLogList_COUNT - [debug,135] - ==> Preparing: SELECT count(0) FROM sys_oper_log
21:23:43.754 [http-nio-8080-exec-20] DEBUG c.r.s.m.S.selectOperLogList_COUNT - [debug,135] - ==> Parameters:
21:23:43.756 [http-nio-8080-exec-20] DEBUG c.r.s.m.S.selectOperLogList_COUNT - [debug,135] - <== Total: 1
21:23:43.757 [http-nio-8080-exec-20] DEBUG c.r.s.m.S.selectOperLogList - [debug,135] - ==> Preparing: select oper_id, title, business_type, method, request_method, operator_type, oper_name, dept_name, oper_url, oper_ip, oper_location, oper_param, json_result, status, error_msg, oper_time, cost_time from sys_oper_log order by oper_id desc LIMIT ?, ?
21:23:43.758 [http-nio-8080-exec-20] DEBUG c.r.s.m.S.selectOperLogList - [debug,135] - ==> Parameters: 10(Long), 10(Integer)
21:23:43.760 [http-nio-8080-exec-20] DEBUG c.r.s.m.S.selectOperLogList - [debug,135] - <== Total: 10
Parameters: 10(Long), 10(Integer):LIMIT的两个参数含义:- 第一个参数
10:查询起始索引 =(pageNum - 1) * pageSize(计算可得:pageNum=2,pageSize=10→ (2-1)*10=10)。 - 第二个参数
10:每页条数 =pageSize(对应前端queryParams.pageSize=10)。 - 结论:当前查询的是「第 2 页,每页 10 条数据」。
- 第一个参数
更多推荐





所有评论(0)