使用 Redis 缓存来实现用户最近浏览的商品列表

一、如何使用 Redis 来缓存来实现最近浏览的商品列表?

首先我们要确定一个两个点,最近浏览的商品肯定是一个一个的操作。

那么就可以确定以下几个问题:

  1. 最近浏览的记录肯定是要有失效时间的

    这里可以使用缓存(Redis等),缓存可以设置失效时间(最大设置为一个月)。

    如果使用关系型数据库,还需要定时清楚,就很不符合实际需求。

  2. 最近浏览记录肯定是要有个数限制的,不可能记录所有的浏览记录

    如果使用Redis来实现的话,Redis 中有 LTRM 来修建,以保证存储的浏览条数。

  3. 需要在哪里添加保存浏览商品的方法。

    用户最近浏览的商品,肯定是要在用户打开商品详情页的时候才算浏览。

  4. 怎么保证每次添加的浏览的商品列表按照浏览的先后顺序排序?

    每次用户的浏览商品的ID,可以以用户的ID作为Key,以 List 作为 value,存储在Redis中,

    而 List 是有序的,并且,在使用 LRANGE 的时候还能保证先进后出,后进先出的原则,以

    达到排列在最前面的商品始终是当前最近浏览的商品。

  5. 怎么保证用户在连续浏览同一商品的时候,不会重复保存商品?

    这里可以使用 Redis 中的 LREM 来移除例表中与参数 value(该商品ID) 想等的元素。

    同时再使用 Lpush 重新再List 中插入最新浏览的商品。

  6. 读取缓存的时候,怎么保证分页?

    Redis 中的 LRANGE 可以指定获取指定长度的元素。

  7. 怎么区别 PC 和 移动端?

    可以让前端根据 PC 和 移动端传不同的code,后台区别code,在 key(用户ID)后面跟上

    特定的字符串来区别。

二、下面是简单的实现思路
  1. 存储用户浏览的商品信息:

    用户在打开商品详情页的时候,以用户ID作为key,商品的Id作为值,以List的形式存到Redis中。

    在加入缓存之前,为了确保浏览商品的唯一性,每次添加之前,使用 LREM 将缓存 List 中的商品id去掉,以保证最新的浏览记录始终在最前面。

    在 Lpush 到 Redis 的list中之后,可以根据需求 保留List中多少条浏览记录

    最后添加缓存失效时间。

  2. 获取用户最近的浏览商品列表:

    根据key(用户ID)及分页数,来获取商品缓存。

三、下面是截取的一段核心代码:
  1. 根据用户ID和商品Id存入到缓存中:

    /**
         * 存一个浏览商品信息
         *
         * @param historyPo
         */
        @PostMapping("/set")
        public void set(@Validated @RequestBody HistoryPo historyPo) {
            String key = getKey(historyPo.getCode(), historyPo.getUserId());
            /* 为了保证浏览商品的 唯一性,每次添加前,将list中该商品ID去掉,再加入,以保证其浏览的最新的商品在最前面 */
            redisService.lrem(key, 1L, historyPo);
            /* 将value push 到该key下的list中 */
            redisService.lpush(key, historyPo);
            /* 浏览记录存5条,五条以后切掉*/
            redisService.lTrim(key, 0L, 4L);
            /* 缓存时间为一个月 */
            redisService.expire(key, DEFAULT_EXPIRE);
        }
  2. 根据用户的ID,分页获取最近浏览的商品:

    /**
         * 获取当前用户的浏览历史
         *
         * @param code
         * @param userId
         * @return
         */
    @GetMapping("/all/{code}/{userId}")
    public List<HistoryPo> query(@PathVariable("code") Integer code, @PathVariable("userId") Long userId) {
        String key = getKey(code, userId);
        //这里可支持分页 start and end
        return redisService.lrange(key, 0L, 9999L);
    
        /* 以下代码解决json反序列化之后集合不能操作问题(例如使用Stream)
            String key = getKey(code, userId);
            List<HistoryPo> lrange = redisService.lrange(key, 0L, 9999L);
            JavaType javaType = getCollectionType(LinkedList.class, HistoryPo.class);
            List<HistoryPo> lst = null;
            try {
                lst = mapper.readValue(lrange.toString(), javaType);
            } catch (IOException e) {
                e.printStackTrace();
            }
            */
    }

    项目完整地址:https://github.com/wengzi/others

相关推荐