初学redis分页缓存方法实现

Posted SeptemberNotes

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了初学redis分页缓存方法实现相关的知识,希望对你有一定的参考价值。

初学redis分页缓存方法实现

使用缓存技术一般是在不经常增删改的数据,我们可以使用缓存技术将第一次请求访问的数据缓存到redis中保存起来,后来的请求的时候首先查询redis数据库是否查询到这些数据,如果存在,则返回数据,如果不存在,则到mysql或其他数据库查询数据返回并保存到redis数据库中。

为什么要采用分页缓存?直接设置缓存,如果数据量大,操作增删改,更新缓存频率高效率低。分页缓存,通过页码设置缓存,可以提高性能。(但是其实不是很好)。

缓存的时候需要考虑的一些问题:

1.新增--删除最后一页缓存(如果倒叙排序,插入数据,第一页改变,后续页列表也都改变,需要删除所有缓存)。
2.修改--更新当前页缓存。
3.删除--更新当前页以及当前页以后的页面的缓存。

上面是分页缓存实现的时候要考虑的一些问题,而我在下面实现的代码并不是这样的,因为我懒得传当前页面cuePage了在add、delete、update的时候,所以,我选择了在add、delete、update的时候都把缓存的分页缓存相关key请理了,更新了分页缓存数据。

    @RequestMapping({"/","index"})
    public String index(Model model,
            @RequestParam(value = "curPage",required = false,defaultValue ="1") Integer curPage){

        //每页展示10条数据
        int pageSize = 5;
        //总数
        int totalRows = userService.getUserByTotal();
        //计算分页
        int totalPages = totalRows / pageSize;
        //可能有余页
        int left = totalRows % pageSize;
        if (left > 0){
            totalPages = totalPages + 1;
        }

        if (curPage < 1 ){
            curPage = 1;
        }

        if (curPage > totalPages ){
            curPage = totalPages;
        }
        //计算查询的开始行

        int startRow = (curPage - 1) * pageSize;
        Map<String,Object> paramMap = new ConcurrentHashMap<>();
        paramMap.put("startRow",startRow);
        paramMap.put("pageSize",pageSize);
        paramMap.put("curPage",curPage);//第几页
        List<User> userList = userService.getUserBypage(paramMap);
        System.out.println("curPage:"+curPage);
        model.addAttribute("userList",userList);
        model.addAttribute("curPage",curPage);
        model.addAttribute("totalPages",totalPages);
        //跳转到模板页面
        return "index";
    }

实现类,缓存总页数。

    @Override
    public int getUserByTotal() 
{
        System.out.println("test:"+userMapper.selectUserByTotal());
        //设置key的序列化方式,采用字符串方式,提高可读性
        redisTemplate.setKeySerializer(new StringRedisSerializer());

        //先从Redis缓存查询
        Integer totalRows = (Integer) redisTemplate.opsForValue().get("totalRows");
        if (null == totalRows){
            synchronized (this){
                totalRows = (Integer) redisTemplate.opsForValue().get("totalRows");
                if (null == totalRows){
                    //去mysql数据库查询总数,并保存到redis缓存中
                    totalRows = userMapper.selectUserByTotal();
                    redisTemplate.opsForValue().set("totalRows",totalRows);
                    System.out.println("从mysql数据库获取totalRows");
                }
            }
        }
        return totalRows;
    }

查询分页缓存,按照查询当前页进行缓存。缓存在redis数据库中的key="curPage1"、key="curPage2"

key="curPage3"、key="curPage*"。

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private RedisTemplate<Object,Object> redisTemplate;

    @Override
    public List<User> getUserBypage(Map<StringObject> paramMap) {
        //设置key的序列化方式,采用字符串方式,提高可读性
        redisTemplate.setKeySerializer(new StringRedisSerializer());

        Integer curPage = (Integer) paramMap.get("curPage");
        List<User> userList = (List<User>) redisTemplate.opsForValue().get("curPage"+String.valueOf(curPage));
        if (null == userList){
            userList = userMapper.selectUserBypage(paramMap);
            redisTemplate.opsForValue().set("curPage"+String.valueOf(curPage),userList);
            System.out.println("从mysql数据库获取userList");
        }
        return userList;
    }

add。添加成功后,mysql数据库+1,redis缓存数据库需要更新一下数据总数的缓存,mysql数据库数据改变了,之前的redis中的分页缓存就不能用了,则在这里删除分页缓存,等下次最新请求访问后先查询mysql,再保存到redsi中。

  @Override
    public int addUser(User user
{
        //设置key的序列化方式,采用字符串方式,提高可读性
        redisTemplate.setKeySerializer(new StringRedisSerializer());

        int add = userMapper.insertSelective(user);
        if (add > 0){
            //添加成功后,mysql数据库+1,redis缓存数据库需要更新一下数据
            int totalRows = userMapper.selectUserByTotal();
            redisTemplate.opsForValue().set("totalRows",totalRows);

            //更新缓存
            Set<Object> keys = redisTemplate.keys("curPage"+"*");
            redisTemplate.delete(keys);
        }
        return add;
    }

delete。删除成功后,mysql数据库-1,redis缓存数据库需要更新一下数据总数的缓存,mysql数据库数据改变了,之前的redis中的分页缓存就不能用了,则在这里删除分页缓存,等下次最新请求访问后先查询mysql,再保存到redsi中。

 @Override
    public int deleteUser(Integer id) 
{
        //设置key的序列化方式,采用字符串方式,提高可读性
        redisTemplate.setKeySerializer(new StringRedisSerializer());

        int delete =  userMapper.deleteByPrimaryKey(id);
        if (delete > 0){
            //删除成功后,mysql数据库-1,redis缓存数据库需要更新一下数据
            int totalRows = userMapper.selectUserByTotal();
            redisTemplate.opsForValue().set("totalRows",totalRows);
            //更新缓存
            Set<Object> keys = redisTemplate.keys("curPage"+"*");
            redisTemplate.delete(keys);
        }
        return delete;
    }

update。update后mysql数据库数据改变了,之前的redis中的分页缓存就不能用了,则在这里删除分页缓存,等下次最新请求访问后先查询mysql,再保存到redsi中。

    @Override
    public int updateUser(User user) 
{
        //设置key的序列化方式,采用字符串方式,提高可读性
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        //boolean b = redisTemplate.delete("curPage"+"*");//
        Set<Object> keys = redisTemplate.keys("curPage"+"*");
        redisTemplate.delete(keys);
        return userMapper.updateByPrimaryKey(user);

    }
redisTemplate模糊匹配删除
        Set<Objectkeys = redisTemplate.keys("curPage"+"*");
        redisTemplate.delete(keys);
        return userMapper.updateByPrimaryKey(user);

下面这样不行的,当时一直很疑惑,只能更新第一页的缓存,后面页的进行add、delete、update后都没有更新。百度一下,换了这么删除key的方法,是可以的。

edisTemplate.delete("curPage"+"*");//这样不行



上面代码的实现缓存并不是很好,缓存需要优雅的使用,并不是所有的项目都需要缓存技术,在使用缓存之前,需要确认你的项目是否真的需要缓存,使用缓存会引入一定的技术复杂度。笔者在这里只是在学习缓存技术时,学习过程中的一些思考与记录。

以上是关于初学redis分页缓存方法实现的主要内容,如果未能解决你的问题,请参考以下文章

php 分页查询怎么redis缓存

基于redis做缓存分页

redis实现分页

php利用redis实现分页列表,新增,删除功能

如何使用 kotlin 实现分页

MongoDB分页获取数据排序阶段缓存溢出问题