对于通过列表展示的数据来说,分页是一个不择不扣的需求,毕竟人类肉眼目所能及的极限摆在那里
如果把分页交给前端搞了话,那么就需要一次性把数据全量查出来,交给前端,浏览器能Hold住多大的数据,会吃掉多少内存,都是一个需要衡量的问题
分页的效果
分页的页面效果如下图所示,效果取自Ant Design Pro
从图中可以看出分页UI的几种交互动作:
- 点击指定页数显示该页数据
- 点击上一页显示上一页数据
- 点击下一页显示下一页数据
- 点击最后一页显示最后一页数据
- 选择每页显示数据条数
- 直接跳转至某页显示该页数据
- 有一个隐藏的交互: 计算总页数, 即最后一页是第几页
这些交互的实现可以由前端来实现,后端只需提供充分的数据支持:
{
"info": {
"total": 100,
"pageSize": 10,
"pageNum": 1
},
"data": [{
......
}]
}
服务端的不同策略
对于分页来说,服务端需要返回的结果,除了该页的数据外,还有该分页的元数据,包括页码(pageNum)、该页数据条数(pageSize)、以及数据总数(total)
对于每页的数据来说,SQL的扩展版已经可以完整的实现了
SELECT * FROM T_Test LIMIT ${OFFSET}, ${SIZE}
只需做一些逻辑上的转换
int offset = (pageNum - 1) * pageSize;
int size = pageSize;
但是total值的获取却有不同的策略
每次点击页码均计算total
这种策略就是在点击某页页码,执行获取该页数据请求的时候,都附加一条计算总数的SQL:
SELECT COUNT(1) FROM T_Test
将该值赋予total返回
打开第一页的时候就请求total
顾名思义,进入列表页面的时候,前端发送请求获取total
之后相关的获取分页数据的操作都不再执行计算总数的操作
这对后端来说需要增加一个单独的接口来计算总条数,然后载入列表页的时候,前端发送两个请求
服务端一次把数据全部查询出来
这种策略,对服务端来说,就不需要用到SQL本身的分页扩展特性
可以使用一个List容器,通过一次查询,装载List请求的所有数据
之后的分页操作则只简单的转化为List的集合操作
这种策略的弊端在于,如果全量数据非常大的话,服务端的内存可能会hold不住这样的量