Redis分页同步问题以及PageHelper分页工具类的定义使用

概述

这个工具类是基于Springboot的PageHelper依赖的

当我们使用Redis进行分页数据同步时,为了避免每次查询都调用数据库创建新的PageInfo对象,所以我们需要自行封装PageInfo的数据。

使用Redis进行分页数据库的数据同步

问题

为了方便数据的修改而不调用大量资源我们不能将所有数据直接封装进Redis中,因为当我们修改其中一条数据时,如果我们使用的是直接将数据写进Redsi中,那么我们只有将该表的所有数据删除然后重新写入数据,当我们数据量庞大时对Redis的压力与速度都是一种挑战

解决方案

这里我使用了Redis的list指向String的数据结构完成数据的存储,并且对分页进行了实现。
list存的是所有数据的地址,String中存的是实际数据,这样我们就可以通过list中的地址访问到实际数据,也可以直接修改我们想要修改的数据,而不是对所有数据进行修改

分页的问题

问题:因为我们实现了分页所以面临着一个新问题,就是我们分页取数据时和数据库取份分页数据一样我们是靠list中的下标取的,如果我们先访问的是第二页那么Redis的list中第一条数据就是第二页的第一条数据,那么当我们访问第一页的数据时,第一页的数据就会存存储在第二页数据之后,这时候数据就会发生错乱。
解决方案:我们可以先对list进行占位然后进行数据的填充,这样就解决这个问题了

代码

这里以对小区数据的同步为例

public class CommunityServiceImpl implements CommunityService{
    @Resource
    private StringRedisTemplate stringRedisTemplate;

    @Resource
    private CommunityMapper communityMapper;

    //redis中所有小区主键
    private static final String ALLCOMMUNITY = "AllCommunity";
    //redis每个小区主键
    private static final String COMMUNITY = "CommunityId:";
    //分页大小
    private static final int SIZE = 2;

    //根据页码查询所有小区
    @Override
    public JsonResult findAllCommunity(int page) {
        ValueOperations<String, String> opsForValue = stringRedisTemplate.opsForValue();
        ListOperations<String, String> opsForList = stringRedisTemplate.opsForList();
        //当前页面第一个元素在数据库中的行号
        int begin = SIZE * (page - 1);
        //当前页面最后一个元素在数据库中的行号
        int end = SIZE * page - 1;
        //判断有没有存数据地址的表
        boolean flag = stringRedisTemplate.hasKey(ALLCOMMUNITY);
        //没有该list表则新建并进行占位
        if (!flag) {
            List list = list();
            for (int i = 0; i < list.size(); i++) {
                opsForList.rightPush(ALLCOMMUNITY, "");
            }
        }
        //获取数据,这个是根据下标获取我们当前页需要的数据
        List listRange = opsForList.range(ALLCOMMUNITY, begin, end);
        //判断listRange是否有数据
        flag = false;
        for (int i = 0; i < listRange.size(); i++) {
            if (listRange.get(i).equals("")) {
                flag = true;
                break;
            }
        }
        //没数据,添加
        if (flag) {
        	//使用PageHelper对数据封装
            PageHelper.startPage(page, SIZE);
            List<Community> listPage = list();
            final int[] temp = {begin};
            listPage.forEach(e -> {
            	//将数据地址存进list
                opsForList.set(ALLCOMMUNITY, temp[0], COMMUNITY + e.getId());
                //将数据存进String
                opsForValue.set(COMMUNITY + e.getId(), JSONArray.toJSONString(e));
                temp[0]++;
            });
            PageInfo<Community> pageInfo = new PageInfo<>(listPage);
            //同样将PageInfo存进Redis中
            opsForValue.set("CommunityPage", JSONArray.toJSONString(pageInfo));
            return ResultTool.success(pageInfo);
        }
        //有数据,取
        //获得之前存进Redis中的PageInfo对象
        PageInfo<Community> pageInfo = JSONArray.parseObject(opsForValue.get("CommunityPage"), PageInfo.class);
        //从list->string中取出实际数据
        List listCommunity = new ArrayList();
        listRange.forEach(e -> {
            String value = opsForValue.get(e);
            Community community = JSONArray.parseObject(value, Community.class);
            listCommunity.add(community);
        });
        //使用PageInfo工具类对数据重新封装
        pageInfo = ChangePageInfo.changePageInfo(pageInfo, listCommunity, page);
        //这里我自定义了一个JsonResult和ResultTool对数据进行处理,如果没写这个工具类,正常返回PageInfo对象就可以了
        return ResultTool.success(pageInfo);
    }
}

PageInfo工具类

下面是使用工具类完成对PageInfo的封装

/**
 *基于Redis的数据同步问题的PageInfo的变化
 */
public class ChangePageInfo {
    /**
     * 查询其他页时PageInfo的变化
     * @param pageInfo      从Redis中取出的pageInfo对象
     * @param data      当前页的数据库数据,类型为list,长度需要与size一样(最后一页的数据可以小于)
     * @param page      当前的页码数
     * @return      新的pageInfo对象
     */
    public static PageInfo changePageInfo(PageInfo pageInfo, List data,int page){
        int begin=pageInfo.getSize()*(page-1);
        pageInfo.setList(data);
        pageInfo.setSize(data.size());
        pageInfo.setPageNum(page);
        pageInfo.setPrePage(page-1);
        if (pageInfo.getPrePage()==0){
            pageInfo.setIsFirstPage(true);
            pageInfo.setHasPreviousPage(false);
        }else {
            pageInfo.setIsFirstPage(false);
            pageInfo.setHasPreviousPage(true);
        }
        if (pageInfo.getPages()==page){
            pageInfo.setNextPage(0);
            pageInfo.setIsLastPage(true);
            pageInfo.setHasNextPage(false);
        }else{
            pageInfo.setNextPage(page+1);
            pageInfo.setIsLastPage(false);
            pageInfo.setHasNextPage(true);
        }
        pageInfo.setStartRow(begin + 1);
        pageInfo.setEndRow(begin + data.size());
        return pageInfo;
    }

    /**
     * 添加数据对PageInfo的变化
     * @param pageInfo      从Redis中取出的PageInfo
     * @return      更改后新的PageInfo
     */
    public static PageInfo insertDataOfPageInfo(PageInfo pageInfo){
        pageInfo.setTotal(pageInfo.getTotal()+1);
        //判断添加后是不是本页第一条数据
        if ((pageInfo.getTotal()%pageInfo.getSize())==1){
            //是的话则新增页码
            pageInfo.setPages(pageInfo.getPages()+1);
        }
        return pageInfo;
    }

    /**
     * 删除数据时对PageInfo的变化
     * @param pageInfo      从Redis中取出的PageInfo
     * @return      更改后新的PageInfo
     */
    public static PageInfo deleteDataOfPageInfo(PageInfo pageInfo){
        pageInfo.setTotal(pageInfo.getTotal()-1);
        //判断删除前是不是最后一页是不是只有一条数据
        if ((pageInfo.getTotal()%pageInfo.getSize())==0){
            //是则删除最后一页
            if (pageInfo.getPages()!=1){
                pageInfo.setPages(pageInfo.getPages()-1);
            }
        }
        return pageInfo;
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值