写点什么

分页合理化是什么?

  • 2023-12-26
    福建
  • 本文字数:2184 字

    阅读完需:约 7 分钟

一、前言


只要是干过后台系统的同学应该都做过分页查询吧,前端发送带有页码(pageNum)和每页显示数量(pageSize)的请求,后端根据这些参数来提取并返回相应的数据集。在 SpringBoot 框架中,经常会使用 Mybatis+PageHelper 的方式实现这个功能。


但大家可能对分页合理化这个词有点儿陌生,不过应该都遇到过因为它产生的问题。这些问题不会触发明显的错误,所以大家一般都忽视了这个问题。那么啥是分页合理化,我来举几个例子:


它的定义:分页合理化通常是指后端在处理分页请求时会自动校正不合理的分页参数,以确保用户始终收到有效的数据响应。


1. 请求页码超出范围:


假设数据库中有 100 条记录,每页展示 10 条,那么就应该只有 10 页数据。如果用户请求第 11 页,不合理化处理可能会返回一个空的数据集,告诉用户没有更多数据。开启分页合理化后,系统可能会返回第 10 页的数据(即最后一页的数据),而不是一个空集。



2. 请求页码小于 1:


用户请求的页码如果是 0 或负数,这在分页上下文中是没有意义的。开启分页合理化后,系统会将这种请求的页码调整为 1,返回第一页的数据。



3. 请求的数据大小小于 1:


如果用户请求的数据大小为 0 或负数,这也是无效的,因为它意味着用户不希望获取任何数据。开启分页合理化后,系统可能会设置一个默认的页面大小,比如每页显示 10 条数据。



4. 请求的数据大小不合理:


如果用户请求的数据大小非常大,比如一次请求 1000 条数据,这可能会给服务器带来不必要的压力。开启分页合理化后,系统可能会限制页面大小的上限,比如最多只允许每页显示 100 条数据。



二、为啥要设置分页合理化?


其实上面那些问题对于后端来讲很合理,页码和页大小设置不正确查询不出来值难道不合理吗?唯一的问题就是如果一次性查询太多条数据服务器压力确实大,但如果是产品要求的那也没办法呀!真正让我不得不解决这个问题的原因是前端的一个 BUG,这个 BUG 是啥样的呢?我来给大家描述一下。


1. BUG 复现


我们先看看前端的分页组件



前端的这个分页组件大家应该很常见,它需要两个参数:总行数、每页行数。比如说现在总条数是 6 条,每页展示 5 条,那么会有 2 页,没啥问题对吧。


那么,现在我问一个问题:我们切换到第二页,把第二页仅剩的一条数据给删除掉,会出现什么情况?



理想情况:页码自动切换到第 1 页,并查询第一页的数据;真实情况:页码切换到了第 1 页,但是查询不到数据,这明显就是一个 BUG!



2. BUG 分析


1. 用户切换到第二页,前端发起了请求,如:http://localhost:8080/user/pageQuery?pageNum=2&pageSize=5 ,此时第 2 页有一条数据;


2. 用户删除第 2 页的唯一数据后,前端发起查询请求,但还是第 2 页的查询,因为总数据的变化前端只能通过下一次的查询才能知道,但此时数据查询为空;


3. 虽然第二次查询的数据集为空,但是总条数已经变化了,只剩下 5 条,前端分页组件根据计算得出只剩下一页,所以自动切换到第 1 页;


可以看出这个 BUG 是分页查询的一个临界状态产生的,必现、中低频,属于必须修复的那一类。不过这个 BUG 想甩给前端,估计不行,因为总条数的变化只有后端知道,必须得后端修了。


三、设置分页合理化


咋一听这个 BUG 有点儿复杂,但如果你使用的是 PageHelper 框架,那么修复它非常简单,只需要两行配置。在 application.yml application.properties 中添加


pagehelper.helper-dialect=mysqlpagehelper.reasonable=true
复制代码


只要加了这两行配置,这个 BUG 就能解决。因为配置是全局的,如果你只想对单个查询场景生效,那就在设置分页参数的时候,加一个参数,如下:


PageHelper.startPage(pageNumber, pageSize, true);
复制代码


四、分页合理化配置的原理说明


这个 BUG 如果要自己解决的话,是不是感觉有点头痛了,但是人家 PageHelper 早就想到这个问题了,就像游戏开挂一样,一个配置就解决了这个麻烦的问题。用的时候确实很爽,但是我却有点担心,这个配置现在解决了这个 BUG,会不会导致新的 BUG 呢?如果真的出现了新 BUG,我应该怎么做呢?所以我决定研究一下它的基础原理。


在 com.github.pagehelper.Page 类下,找到了这段核心源码,这段应该就是分页合理化的实现逻辑


// 省略其他代码public Page<E> setReasonable(Boolean reasonable) {  if (reasonable == null) {    return this;  }  this.reasonable = reasonable;  //分页合理化,针对不合理的页码自动处理  if (this.reasonable && this.pageNum <= 0) {     this.pageNum = 1;     calculateStartAndEndRow();   }   return this;}// 省略其他代码
// 省略其他代码/** * 计算起止行号*/private void calculateStartAndEndRow() { this.startRow = this.pageNum > 0 ? (this.pageNum - 1) * this.pageSize : 0; this.endRow = this.startRow + this.pageSize * (this.pageNum > 0 ? 1 : 0);}// 省略其他代码
复制代码


还有一些代码我没贴,比如 PageInterceptor#intercept 方法,这里我整理了一下它的执行流程图,如下:



看了图解,这套配置还挺清晰的,懂了怎么回事儿,用起来也就放心了。记得刚开始写代码时,啥都希望有人给弄好了,最好是拿来即用。但时间一长,自己修过一堆 BUG,才发现只有自己弄明白的代码才靠谱,什么都想亲手来。等真正搞懂了一些底层的东西,才意识到要想造出好东西,得先学会站在巨人的肩膀上。学习嘛,没个头儿!


文章转载自:sum墨

原文链接:https://www.cnblogs.com/wlovet/p/17926629.html

体验地址:http://www.jnpfsoft.com/?from=001

用户头像

还未添加个人签名 2023-06-19 加入

还未添加个人简介

评论

发布
暂无评论
分页合理化是什么?_分页操作_不在线第一只蜗牛_InfoQ写作社区