如何处理 api 分页导致的数据重复或丢失

2016-12-20 10:26:11 +08:00
 bigbyto

我们的 api 目前是这样设计的

/users/?page=2&pre_page=20

客户端提交页数和每页的数量,服务端返回如下

{
   "code": 0,
   "pagination": {
      "page": 1,
      "limit": 20,
      "total": 100
   }
   
   "data": {}
}

不过这样会出现数据重复或丢失。比如当前用户正在 app 翻页刷新,如果正好在后台删除了一条消息,那么就会因为数据变化导致分页时有一条数据丢失了。

后来想到一个解决方案,通过 cursor 分页

/users/?cursor=2015-01-01 15:20:30&limit=10

上面就可以解决 app 端翻页时数据出现变化的情况,不过依然会有 2 个严重的问题。

  1. 时间戳重复会导致永久丢失某条数据
  2. 如果存在筛选条件(如饿了么按照经纬度排序获取数据),此方法失效

对于第一个问题,我们想到使用主键作为过滤条件(主键递增),可以解决重复的问题。但第二个问题似乎想不出什么好的办法。

不知道大家怎么处理分页问题,有好的建议或方案还望不吝赐教。

11562 次点击
所在节点    程序员
38 条回复
dou4cc
2016-12-20 10:36:38 +08:00
不要搞太复杂
把页面做成自动更新的,使后台对数据的操作实时反映在页面上
stamaimer
2016-12-20 10:37:47 +08:00
你可以看看 twitter 咋做的
BOYPT
2016-12-20 10:39:50 +08:00
学习 twitter 的 api 设计,使用 sinceid , lastid ; 推算 page 难维护难想难写容易错。
q397064399
2016-12-20 10:40:20 +08:00
这个不应该是后端的事情么?
脏读 可以通过事务控制来 防止
learnshare
2016-12-20 10:40:35 +08:00
大部分场景下不需要考虑客户端状态同步

如果真的需要,可以把删除动作同步到客户端;然后分页使用 itemId 作为判断依据,而不是 page + size
xiaoyangsa
2016-12-20 10:43:10 +08:00
@learnshare 说得对,客户端不要搞太复杂。用 itemid 来分页吧。
Ge4Los
2016-12-20 10:51:17 +08:00
用游标加长度来做参数。这种类似的 feed 流的接口,内容总在更新,客户端接口就适合游标了。
loading
2016-12-20 10:59:32 +08:00
传入数据库的 id 字段
bigbyto
2016-12-20 11:02:00 +08:00
@BOYPT 谢谢,我去查一下 twitter 的分页方案。
bigbyto
2016-12-20 11:03:15 +08:00
@learnshare
@Ge4Los
@loading

使用游标或 id 一旦出现筛选条件就会失效了,有没有一种通用的方案呢。
murmur
2016-12-20 11:04:39 +08:00
丢了就丢了呗,你看新浪微博刷新一次直接时间起飞到上个世纪,一样股票大涨
chairuosen
2016-12-20 11:08:11 +08:00
丢就丢了+1
ty89
2016-12-20 11:10:45 +08:00
按 lastid 来分页,只适合按照时间排序类似微博这种,万一后来来个需求让你按照热度、点赞数、评论数来生序降序就呵呵了
bigbyto
2016-12-20 11:13:38 +08:00
@ty89 对啊,我担心的问题就在这里。按照 id 分页,一旦将来增加排序需求的话完了。
quericy
2016-12-20 11:29:51 +08:00
我们就是动态排序的,按照 Redis 里 SortSet 得分从高到低
当时想到个分页方案是以得分作为游标,这样每次翻页的时候获得得分更低的指定条数数据.
而顶贴的时候得分会更新得更高,不会出现重复的问题,
但是可能会漏掉几条翻页过程中被顶上去的帖子.

不过这个方案没通过,最后还是用了传统分页+客户端对近几页的帖子 ID 去重
ofblyt
2016-12-20 11:35:42 +08:00
个人觉得只能是按照 id 排序来进行分页,包括美团在内的公司对于多维度排序的处理也只是将主要纬度的数据分别建表,按各个纬度的 id 进行排序分页
Miy4mori
2016-12-20 11:58:10 +08:00
这有什么影响吗?不要做的太复杂。
morethansean
2016-12-20 12:00:42 +08:00
为什么不按照时间戳呢
dotudeth
2016-12-20 12:00:55 +08:00
@learnshare 如果这个列表还掺杂着排序的操作呢(比如在后台设了权重值)。
sorra
2016-12-20 12:09:42 +08:00
办法是有,数据库与缓存做 diff 比较,但是颇为复杂。
写文一篇 http://www.qingjingjie.com/blogs/24

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/328806

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX