一、Offset-based Pagination
基于偏移的分页是几乎所有现代框架中最常见的即用型解决方案。 可以指定参数limit,offset和page等来指定所需的一组特定结果。
查询方式
http://abc.dd.com/list?page=n&count=n
缺点
1.随着数据集的增长,性能变慢,因为会查询页码前面的所有数据。比如select * from msgs limit 100000, 100; 会查询前100100条数据。
2.结果集数据条数发生变化,导致查询数据不准确,在某些情况下,还会返回重复的结果。
优点
可以随意选择页码查询,可以跳页码。
应用场景
管理后台
二、Cursor-based Pagination
基于游标的分页是最有效的技术,可提供最准确的结果。 光标是指指向数据集中特定项目的键集。 它充当记录的指针。 调用API时,可以将键集与请求一起传递,以获取游标之前或之后的数据。 还可以传递limit参数来限制返回结果集。
查询方式
http://twitter.com/followers/ids/barackobama.xml?cursor=-1
优点
1.性能更好,查询速度更快。 比如 select * from msgs where id > cursor_id limit 100;只会查询100条数据。
2.可以按大型数据集进行缩放,并且还提供一致的结果。不会因为数据条数变化导致结果集不准确
缺点
只能从头开始查询连续的页;无法提供记录总数,还阻止跳转到特定页面
应用场景
大数据集翻页可以采用这种cursor方式。基于cursor的分页的最佳用例是创建带有无限滚动的页面。假定数据集变化非常频繁,并且用户可以经常从用户新闻提要,帖子等中拉出数据集。Twitter和Facebook都是使用这种方式。App端的分页常用这种方式。
Twitter Cursor Based Pagination事例:
https://api.twitter.com/1.1/search/tweets.json?q=php&since_id=24012619984051000&max_id=250126199840518145&result_type=recent&count=10
Facebook API Cursor Based Pagination事例:
{
"data":[
{....},
{....}
],
"paging":{
"cursors":{
"after":"MTAxNTExOTQ1MjAwNzI5NDE=",
"before":"NDMyNzQyODI3OTQw"
},
"previous":"https://graph.facebook.com/me/albums?limit=25&before=NDMyNzQyODI3OTQw",
"next":"https://graph.facebook.com/me/albums?limit=25&after=MTAxNTExOTQ1MjAwNzI5NDE="
}
}
三、注意事项
1.基于cursor的分页,一定要排序;cursor最好是数据库中自增id,有序,而且全局唯一,这种情况下实现比较简单。在数据库中可以通过大于或者小于查询到下一页或者上一页的数据。
2.如果数据库中没有自增的id,cursor可以选用其他的字段,但是该字段一定要是数字类型,这样可以通过大于或者小于查询到下一页或者上一页,比如ctime等时间戳。
3.使用ctime做cursor的问题是:并发较高时,ctime容易出现重复。
-
a.解决办法,cursor使用 ctime加一个唯一键比如order_i段,然后使用base64+对称加密对ctime+order_id生成一个字符串,生成的该字段作为cursor.
-
b.查询时,比如每页查询出20条,后端解密出 ctime+order_id,根据ctime查询出该时间点有多少条数据,假如有3条数据,where ctime > ctimeValue and limit 20+3; 一共查询到23条数据,然后通过order_id找到需要的20条数据。
-
c.根据新的数据生成新的cursor并返回。
关注公众号,输入“java-summary”即可获得源码。
完成,收工!
【传播知识,共享价值】,感谢小伙伴们的关注和支持,我是【诸葛小猿】,一个彷徨中奋斗的互联网民工。