菜菜哥, 我又来了
晚上请我喝咖啡吗?
那你得先帮我解决一个问题
说来听听
昨天加班很晚排查一个分页引起的问题, 到现在还没解决, 心情有点抑郁, 需要安慰
说来听听
我们新做的商城首页是一个分页的商品的列表, 昨天运营反应, 加载出来的商品偶尔有重复的, 但是我本地和测试服务器都没问题, 代码是没问题的
分页是怎么写的呢?
就是传统的那种, 客户端上传 pagesize 和 pageindex 两个参数, 然后服务端根据排序规则去排序
那我可能知道怎么回事了, 晚上咖啡我喝定了
问题分析
通过以上的对话, 身为程序员的你是否也遇到过妹子这样的问题呢? 传统的而且网上到处充斥着的也是这类方式, 客户端根据自己的滚动不断的更新 pagesize 和 pageindex 两个参数, 然后上传给服务端接口获取数据, 而且网络上也很少说明这种方式是否有问题, 那到底有没有问题呢?
谈到分页, 无论程序怎样写, 分页这个业务的核心动作是根据开始位置和结束位置来获取一段数据, 无论你的排序规则有多复杂, 最终的目的总是获取总列表数据中一段连续的数据. 无论你是直接用的 sql 语句分页, 还用的搜索引擎(比如 es), 最终在客户端体现的效果就是下一页的数据展现.
当然体现在客户端的 UI 上的交互操作可以有很多样式
如果是瀑布流或者 App 段滚动展示的方式, 或者其他不需要数据总个数的情况下, 菜菜认为服务端千万不要查询这个总个数数据, 展示方完全可以以下一页有无数据作为是否继续拉取下一页数据的依据.
话题回归, 如果客户端依据 pagesize 和 pageindex 参数来进行分页需求, 有没有问题呢? 当然有, 要不然菜菜写这篇文章意义何在, 我又不是一个喜欢爱扯淡的程序员~~
问题所在
这里以最简单也是最基本的 sql 语句分页为例, 假如现在数据库现有数据为
1,2,3,4,5,6,7
排序的规则是按照大小倒序, 即数据的全部列表为:
7,6,5,4,3,2,1
假如现在是获取第二页数据, pagesize 为 2,pageindex 为 2, 正确结果为 "5,4" . 这无可厚非, 在数据未发生改变的情况下, 正确结果确实如此, 那如果数据发生的变化呢, 假如现在新加入一条数据 8, 列表数据会变为
8,7,6,5,4,3,2,1
那依据以上分页原则, 第二页获取的数据就变为了 "6,5", 聪明的你是不是发现了问题, 这也可能是 D 妹子引发加班的原因.
分页的操作是建立在动态数据上的操作
解决问题
分页操作的数据源是动态变动的, 有时候变动的部分正好发生在你获取的数据范围内, 就会发生数据重复或者错误的情况. 那怎么解决呢?
客户端
作为数据的需求方和展示方, 客户端需要记住已经加载的数据的主键列表, 如果某条数据已经展示过, 根据业务需求来确定是否要重复展示, 一般情况下需要去重.
如果数据量非常大, 客户端维护一个数据池的方案其实也不够理想
服务端
1. 服务端分页接口参数新增上一页最后一条数据 id 参数 lastId, 去掉 pageindex 参数, 因为在多数情况下, pageindex 参数在服务端的作用是确定数据的起点而已, 如果有了 lastid,pageinde 在很多情况下其实已经不需要了.
2. 服务端把所有的数据做缓存, 这样动态数据在一定时间内静态化, 但是这样也是治标不治本.
3. 如果业务上对于排序无要求的话, 服务端可以采用顺序分页, 把获取的数据落在不会变动的数据段上
服务端要想把动态的数据搞成静态有点难度
业务方
无论程序怎么优化也改变不了数据是在不停变动的本质, 如果业务方 (产品, 运营) 能够接受数据在偶尔情况下能重复的现象, 那能大幅度减少程序员的工作了.
有时候你认为的数据 bug, 在其他业务部门不一定是什么重大问题.
THE END
●程序员修神之路 -- 问世间异步为何物?
●程序员修神之路 -- 提高网站的吞吐量
●程序员修神之路 --分布式高并发下 Actor 模型如此优秀
●程序员过关斩将 -- 论商品促销代码的优雅性
●程序员过关斩将 -- 请不要随便修改基类
●程序员过关斩将 -- 你的面向接口编程一定对吗?
●程序员修神之路 -- 高并发下为什么更喜欢进程内缓存
●程序员修神之路 -- 高并发优雅的做限流
来源: https://www.cnblogs.com/zhanlang/p/10851427.html