关于分页的研究

最近在做项目的时候,遇到了需要分页的情况,对前段时间碰到的分页和思考进行一个总结。

按照使用的场景不同,分页可以分为两大类,不跨页的分页和跨页的分页

不跨页的分页是指由一个分页切换到下一个分页,这两个分页面是相邻的,跨页分页是指上一个分页和下一个分页之间不一定相邻

本文要研究的主要是不跨页的分页,这种方式常见于手机端,各种APP里面通过拖动操作来拉取下一页的操作。

不跨页的分页的分页机制是后端返回给前端一个分页的数据以后,比如(n+1,2n)数据,其中会有一个分页字段,前端需要拉取下一个分页的数据时,需将编号为2n的那条记录的分页字段和拉取的条数传给后端,后端再返回下一个分页的数据,作为分页的分页字段有一个特点是不可以重复。

在不跨页的分页范畴类,还可以再进行一层划分,即通过数据库sql来实现分页和程序进行分页两类

sql分页指通过sql语句查询出来的结果集已经是按照要求分页好的数据,不需要再做处理,程序实现分页指数据库查询出来的结果集并不是已经分页好的数据,需要自己在程序中编
码实现分页

由于分页常与排序,筛选等结合在一起,所以对这三者的组合也分情况进行讨论。以下面的用户表为例

user

id user_id sex grade create_time
1 100393 1 1 2018-02-02
id user_id sex grade create_time
1 100393 1 1 2018-02-02
2 100395 2 1 2018-02-02
3 100396 1 1 2018-03-03
4 100394 1 2 2018-03-03
5 100398 1 2 2018-04-04
6 100397 2 2 2018-04-04
前端与后端交互的数据规则为,前端每次传入分页的最后一条记录的分页字段的值,和要拉取的条数,如果是拉取第一页的记录,则传入的分页字段的值为空;

1.单纯的分页,无排序与筛选,这种可以通过sql直接分页

第一次分页返回前两条数据,用户需要拉取下一页两条数据,以id作为分页字段

select * from user order by  id asc limit 2,2

2.分页与筛选的结合,这种情况和第一种情况一样,可以通过sql直接分页,还是以id作为分页字段

比如需要筛选优先等级为1的用户,同时支持分页

第一次拉取了前两条,拉取第二页

select * from user where grade = 1 order by id asc limit 2,2

3.分页与排序的结合,比比如需要按照优先等级从高到低进行排序吗,同时需要支持分页

如果以数据库sql的语句直接分页,则拉取第一次的记录

select * from user order by grade desc limit 0,2

第一个拉取了两条,6号和5号记录,5号记录的grade值为2,现在拉取第二页的数据

select * from user where grade <2 order by id desc limit 2,2

这是查询出来的为3号和2号记录,并不是预期的4号和3号记录,为什么会出现这样的情况呢,这是因为排序字段本身作为分页字段的grade并没有唯一性,而是可重复的,如果采用可重复的字段作为分页的字段,则就会出现两个相邻的分页之间会出现断层,即有遗漏的数据没有返回。这是需要想另外的办法来实现分页

1).若数据库中的某个字段与要排序的字段具有排序一致性,即当排序字段为增序时,该字段也为增序,排序字段为降序时,该字段也为降序,同时该字段由具有唯一性,则可以利用该字段来实现分页

比如上面若假定id与grade具有排序一致性,则可以利用id作为分页字段,第一次的语句为

select * from user order by grade desc limit 0,2

查询结果仍然为6号和5号记录,5号记录的id值为5,拉取第二页的记录的语句:

select * from user where id < 5 order by grade desc limit 0,2

查询的记录为4号和3号记录,不会出现断层。

2)在程序里面进行分页,这种分页的方法为选取一个字段作为分页字段,这个字段不需要与排序字段具有排序一致性,但是需要也是唯一的。比如上例中,以user_id作为分页字段

在数据库中对整个结果进行排序,数据库查询语句为

select * from user order by grade desc

这是会查出整个结果,在程序中进行分页,第一次拉取了6号和5号记录,先拉取第二页的数据

 

for(Record bean:recordList){

     if(userId!=null){//userId为前端传入给后端的分页字段的值

  if(userId.equal(bean.getUserId()))

 {

 userId=null;

}

 }else{

  list.add(bean);

 if(list.size()>pageCount){

 break;

 } 

 }

}

这段分页程序的运行逻辑为:

userId为前端传入给后端的分页字段的值,每次调用时,都会从整个结果集的第一个元素开始进行遍历。

拉取第一页的数据时,userId为空,遍历时每次都会进入else语句,直接返回前pageCount条记录,假定pageCount为2,

则拉取的为6号和5号记录,5号记录的user_id值为100398

拉取第二页的数据时,传入的userId值为100398,程序还是会从6号用户开始遍历,这里userId有两个作用,一个是作为一个开关值,其二为判断是否首页

遍历前面count-1条数据的时候,由于不满足条件,userId开关状态一直保持不变,相当于开关一直处于关闭状态,当遍历到前端传过来的userId条记录时,这是满足条件,开关值userId的状态发生改变,相当于开关打开,后面的每条数据都会进入列表,列表中有count条数据以后会再次跳出循环。

4.分页与筛选,排序三者的结合,这种情况与第3种情况采用一样的处理方式即可。

总结:

当分页或者分页与筛选结合时,采用数据库sql语句分页就可以;

当有排序参与时,如果要排序的字段具有不重复的特点,则可以同时使用排序的字段作为分页字段,采用sql语句实现分页

若果要排序的字段可能出现重复,则采用另外一个字段作为分页字段,分情况使用sql分页和程序分页。


猜你喜欢

转载自blog.csdn.net/w450093854/article/details/79246196