在很多网站都有进行数据分页,那么大家一定有疑问为什么要进行数据分页,数据分页又是怎么实现的?
目录
1.数据分页的必要性
-
前端性能和用户体验:
- 减少加载时间:如果一次性加载所有数据,可能导致长时间的加载等待。分页可以减少单次加载的数据量,从而加快页面响应时间。
- 提升用户体验:分页使得用户可以更方便地浏览和定位数据,避免了滚动条过长导致的操作不便。
- 减轻浏览器负担:大量数据同时渲染可能导致浏览器卡顿或崩溃,分页可以有效减轻浏览器的渲染负担。
-
后端性能和资源管理:
- 减轻服务器负担:一次性处理和返回大量数据会对服务器造成很大压力,分页可以显著减轻服务器的处理负担。
- 优化数据库查询:分页可以减少数据库的查询负载,特别是对于大型数据库,这可以大幅提高查询效率。
- 节省网络资源:传输大量数据会消耗大量网络带宽。通过分页,每次只传输需要的数据量,可以有效节省带宽资源。
-
数据管理和安全:
- 更好的数据管理:对于后台管理系统,分页可以帮助管理员更有效地管理数据,快速定位和处理数据。
- 安全考虑:在一些应用中,为了数据安全,限制一次可以访问的数据量是非常重要的。
2.数据分页的实现
2.1实例分析
首先我们拉起RuoYi找到有数据分页功能的页面,在这里我以日志管理的登陆日志功能为例,因为数据条数比较多,便于我们分析。
进入系统管理 ——日志管理——登陆日志
2.2源码分析
2.2.1前端
pageNum
表示当前的页码。这里初始化为 1
,意味着默认情况下加载第一页的数据。这是分页功能中的一个常见参数。
pageSize
表示每页显示的数据条数。这里设置为 10
,意味着每页将显示 10 条数据。这个参数用于控制分页组件每页显示数据的数量。
用开发者工具查看前端访问后端的情况
.then(response => {...})
:
- 当
list
函数的异步操作完成后,.then
方法会被调用。 response
是从服务器返回的数据。
更新组件状态:
this.list = response.rows;
:将返回的数据中的rows
属性赋值给组件的list
属性。this.total = response.total;
:将返回的数据中的total
属性赋值给组件的total
属性。total
表示数据的总数。
2.2.2后端
2.2.2.1 startPage()
总结来说,startPage()
在 BaseController
中作为一个方便子类控制器调用的方法被定义。SysLogininforController
作为 BaseController
的子类,在处理请求时调用了这个方法来设置分页。而 BaseController
的 startPage()
方法内部调用了 PageUtils.startPage()
,后者负责实际的分页逻辑处理。
2.2.2.2 getDataTable(list)
getDataTable
方法是一个通用方法,用于将查询到的列表数据和分页信息封装成一个标准化的响应格式。
在这里就出现了一个问题:我们前面看到total 值大于list 长度,那如何通过list 做到的?
答案是通过new PageInfo(list).getTotal();
这里对于强制类型转化然后调用不太理解的可以先跳到3.强制转化的简单示例
2.2.2.3分页实现原理分析
那么我们来分析打印的logSQL 被MyBatis 拦截改变了,selectLogininfirList 函数对应两句SQL:
一句查询表的总行数[count(0)]
一句对查询数据做了行数输出限制[LIMIT 10]
对应前端参数pageNum=1&pageSize=10 count(0):
表数据的总行数 LIMIT 有两种形式:
LIMIT num:数据的前num 个
LIMIT offset,num:从offset 偏移位置开始的num 个数据
MyBatis 通过startPage 中的函数PageHelper.startPage 做到了对SQL 语句的修改
MyBatis 通过修改SQL 语句,多请求了一句SQL 语句:SELECT count(0) FROM sys_logininfor 返回了总行数给到Page 对象的total 成员。然后通过子类Page 强转父类List 对象,访问其成员total 值,赋值给PageInfo 父类成员total,即this.total = ((Page)list).getTotal();
2.2.2.3分析LIMIT后面值的含义
LIMIT
子句的参数为 10(Long), 10(Integer)
。这里,第一个参数 10
表示查询结果的起始位置(偏移量),第二个参数 10
表示查询结果的最大行数(数量)。
由于 SQL 分页是基于 0 开始的,pageNum=2
和 pageSize=10
意味着要查询第二页的数据,每页有 10 条记录。因此,查询的起始位置是 10
(第二页的起始索引是 1 * pageSize
),数量仍然是 10
。
这个 SQL 查询是为了获取第二页的数据,每页显示 10 条记录。由于分页索引从 0 开始,所以第二页的数据实际上是从第 11 条记录开始的,一直到第 20 条记录。
通过这种方式,后端服务能够根据前端请求的页码和页面大小,有效地从数据库中检索出所需的数据范围,以实现分页功能。
3.强制转化的简单示例
3.1自定义一个类MyPage
MyPage继承List,成员含有公有成员total
3.2定义函数selectTotalList
返回类型List<>。函数功能为创建一个MyPage对象,设置成员total 为100,函数返回MyPage 对象
3.3调用 selectTotalList
从返回的List 对象中输出total 的值
输出结果: