likes
comments
collection
share

什么,小小的分页居然暗藏玄机?

作者站长头像
站长
· 阅读数 19

前言

  • 数组分页
  • RowBounds内存分页
    • RowBounds是将所有符合条件的数据全都查询到内存中,然后在内存中对数据进行分页,若数据量大,千万别使用RowBounds
  • 分页插件拦截器limit分页
  • sql手写limit分页

其中工作中使用最多的是使用分页插件进行拦截sql语句分页,但工作中也有一些较为复杂的情况,是不可以直接使用分页插件进行分页的(直接使用的话可以能造成数据丢失)。以下分享笔者在工作中遇到的案例,仅供参考。

正文

示例实体类如下,其他Mapper、Service方面使用MybatisPlus即可。数据请自行添加。

@Data
@NoArgsConstructor
@AllArgsConstructor
@ToString
public class Country {
    private Integer id;
    private String countryname;
    private String countrycode;
}

一般的分页形式为以下

@Test
public void testPage() {
    PageHelper.startPage(1, 10);
    List<Country> list = countryService.list(new QueryWrapper<>());
    PageInfo pageInfo = new PageInfo(list);

    System.out.println(list);
    // 正常的显示10条
    System.out.println(pageInfo);
}

什么,小小的分页居然暗藏玄机? 这种情况直接使用分页插件就能完成需求,是一般的业务场景。

但有时会遇到以下这种情况

@Test
public void testPage2(){
    PageHelper.startPage(1, 10);
    List<Country> list = countryService.list(new QueryWrapper<>());
    // 分页查找后还需要下一步筛选处理
    List<Country> countryList = list.stream().filter(x -> !x.getCountrycode().equals("US")).collect(Collectors.toList());
    PageInfo pageInfo = new PageInfo(countryList);

    //此时查出来的数据就不是10条了
    System.out.println(countryList);
    System.out.println(pageInfo);
}

分页查找后进行下一步筛选处理的话,会损失一部分数据,这样出来的结果就不一定是10条了。

什么,小小的分页居然暗藏玄机? 而且可以注意到total的数量也不对,这是明显不符合业务需求的。

这下该怎么办呢?

什么,小小的分页居然暗藏玄机?

以下提供几种笔者用到的解决思路,视情况而定,仅供参考。

第一种

最简单实用的一种方法,可以先了解清楚业务需求,把筛选处理这一步骤放到sql语句中。

示例如下所示

@Test
    public void testPage3(){
        PageHelper.startPage(1, 10);
        QueryWrapper<Country> wrapper = new QueryWrapper<>();
        wrapper.ne("countrycode", "US");
        List<Country> countryList = countryService.list(wrapper);
//        List<Country> countryList = list.stream().filter(x -> !x.getCountrycode().equals("US")).collect(Collectors.toList());
        PageInfo pageInfo = new PageInfo(countryList);

        System.out.println(countryList);
        System.out.println(pageInfo);
    }

什么,小小的分页居然暗藏玄机?

第二种

也有一些情况是处理十分复杂,不能写在sql里面的。这种情况的话建议先看数据量大小,如果数据量不算大的话,可以查出全部数据,经过处理后再手动进行分页拼装。

示例如下

@Test
    public void testPage4(){
        int page = 1;
        int size = 10;
        QueryWrapper<Country> wrapper = new QueryWrapper<>();
        List<Country> list = countryService.list(wrapper);
        // 模拟复杂处理
        List<Country> countryList = list.stream().filter(x -> !x.getCountrycode().equals("US")).collect(Collectors.toList());
        // 手动分页
        List<Country> pageCountryList = countryList.stream().skip((page - 1) * size)
                .limit(size)
                .collect(Collectors.toList());
        // 拼装分页
        PageInfo pageInfo = new PageInfo(pageCountryList);
        pageInfo.setTotal(countryList.size());
        pageInfo.setPageSize(size);
        pageInfo.setPageNum(page);
        pageInfo.setPages(countryList.size() / size + 1);

        System.out.println(countryList);
        System.out.println(pageInfo);
    }

什么,小小的分页居然暗藏玄机? 这样就可以即进行处理也不丢失分页了 什么,小小的分页居然暗藏玄机?

第三种

不过也有一个问题,要是数据量大的话呢? 数据量大就会造成接口耗时过长,用户体验不好。那该如何是好呢?

这种情况干脆开摆不就好了嘛(不是)

什么,小小的分页居然暗藏玄机?

遇到这种情况需要先分析查询的数据是什么数据,如果这部分数据是写入不频繁的话,可以使用Redis缓存,在启动的时候就把数据缓存起来,这样的话就可以解决数据量大耗时过长的问题了。

那该如何知道数据是否写入频繁呢,笔者建议可以询问同事,或者直接把这种情况汇报给领导,如果错误的判断数据的写入频率而盲目的使用Redis缓存,可能会造成不必要的bug和线上问题。

第四种

如果这部分数据是写入频繁的呢?

这种情况笔者遇到的次数较少,近期工作中遇到过一次,笔者的解决方法如下:

  1. 跟领导汇报反应情况,根据接口的重要性决定是否优化(很重要)
  2. 分析了解这部分代码的业务需求
  3. 根据代码的业务需求场景进行重构

后记

实际情况复杂多变,有时改了一堆代码但事与愿违,也有时只要改改sql语句就行。事在人为,各位尽力优化分页就好。

转载自:https://juejin.cn/post/7375073395316604955
评论
请登录