今天做一个小项目要用到redis查询,遇到一个很奇怪的现象:
使用redis缓存一个list,然而我发现每次缓存完后,第二次获取是正常的,第三次的时候缓存就又丢了,如此反复。
代码如下:

public List<ItemCat> selectAllByStatus(int status) {
        List<ItemCat> itemCats = null;
        try {
            //从redis中获取存放分类信息的缓存
            itemCats = (List<ItemCat>) redisTemplate.opsForList().leftPop("itemCats",0,0);
            //没有缓存,从数据库中获取并存入缓存
            if(itemCats==null || itemCats.isEmpty()){
                itemCats = itemCatMapper.selectAllByStatus(status);
                redisTemplate.opsForList().leftPush("itemCats",itemCats);
            }
        } catch (Exception e) {
            //连接服务器有异常
            itemCats = itemCatMapper.selectAllByStatus(status);
            e.printStackTrace();
        } finally {
            return itemCats;
        }
    }

我越看越奇怪,虽然是spring提供的redis工具,但是leftPop应该和原生指令是一致的也即是:LPop指令

LPOP key
移除并返回列表 key 的头元素。
可用版本:= 1.0.0
时间复杂度:
O(1)
返回值:
列表的头元素。
当 key 不存在时,返回 nil 。

pop是弹出操作,弹出后回删此元素,也就解释了为什么会一次有缓存一次没有缓存的问题。


解决思路:查阅了redis的api,想起来获取而不删除的命令应该是range,再去翻阅spring RedisTemple的api文档,果然有range方法。

下面是来自didier-spezia的回答

You can easily peek at an item rather than popping it by using the range command.
With Spring, from a RedisTemplate instance, you can get a ListOperations instance by using the opsForList() method, and then:
listOp.range(key, 0, 0) will return the first (left) item without popping it
listOp.range(key, -1, -1) will return the last (right) item without popping it
See documentation at:
http://static.springsource.org/spring-data/data-keyvalue/docs/1.0.x/api/org/springframework/data/keyvalue/redis/core/RedisTemplate.html http://static.springsource.org/spring-data/data-keyvalue/docs/1.0.x/api/org/springframework/data/keyvalue/redis/core/ListOperations.html

大致意思是,如果想根据key获取某个元素,应该是使用 listOp.range(key, 0, 0)方法或者 listOp.range(key, -1, -1),主要区别是一个是从第一个(左边)还是从最后一个(右边)位置来获取。

//将leftPop改为range方法就欧克
itemCats = (List<ItemCat>) redisTemplate.opsForList().range("itemCats",0,0);

2020-11-7更新:经测试后发现range方法把list封装过一次,导致前端有问题,新的解决思路是:使用index方法!!

//从redis中获取存放分类信息的缓存 要用index方法!!!!
 	itemCats = (List<ItemCat>) redisTemplate.opsForList().index("itemCats",-1);