阅读 194

redis分布式缓存(十三)一一 京东购物车解决方案

一、京东购物车多种场景分析

步骤1:先登录你的京东账号,查看购物车里商品。 (如有1件商品在购物车)

步骤2:先退出登录,再在无登录状态下的购物车中添加商品B,然后关闭浏览器再打开。

步骤3:再次登录你的京东账号。(购物车里已加入退出登录时加入购物车的商品,和登录时购物车商品进行了合并)

注:最近发现京东商城的购物车已经需要登录才能加入购物车了。

二、高并发的京东购物车技术实现

  1. 登录状态下添加商品到购物车

1.添加购物车2.写入redis3.异步写入db写入登录状态购物车服务Redis消息中间件MQDB

在高并发的情况下,登录用户添加购物车,购物车服务把数据存储在redis然后发消息给消息中间件最后消费中间件的数据写入数据库

这种高并发情况,就能保证所有的查询操作都能落在reids上,从而使数据平稳持久化到db。

  1. 未登录状态下添加商品到购物车

1.添加购物车2.写入redis未登录状态购物车服务Redis

未登录用户添加购物车,购物车服务为该用户生成唯一id: cartId,并把该cartId作为key,把购物车的数据保存进redis(有效期3个月),最后购物车服务把该cartId回写进用户的cookies

这个环节不保存数据库了,因为没有对应的用户。以后用户每次添加商品都带上这个cartId就行,

  1. 再登录状态合并

1.登录后合并购物车请求2.合并写入db3.刷新再登录状态购物车服务DBRedis

用户登录成功后,客户端把cookies里面的cartIduserId发给购物车系统,购物车系统通过cartId把redis未登录的数据合并插入到该userId的数据库里面。

最后重新刷新添加到登录userId的redis数据,删除未登录carId的redis数据。

三、购物车的redis经典场景

往购物车加入2件商品 采用hash数据结果,key=cart:user:用户id hash=《商品id,数量》

127.0.0.1:6379> hset cart:user:1000 101 1 (integer) 1 127.0.0.1:6379> hset cart:user:1000 102 1 (integer) 1 127.0.0.1:6379> hgetall cart:user:1000 1) "101" 2) "1" 3) "102" 4) "1" 复制代码

修改购物车的数据,为某件商品添加数量

127.0.0.1:6379> hincrby cart:user:1000 101 1 (integer) 2 127.0.0.1:6379> hincrby cart:user:1000 102 10 (integer) 11 127.0.0.1:6379> hgetall cart:user:1000 1) "101" 2) "2" 3) "102" 4) "11" 复制代码

统计购物车有多少件商品

127.0.0.1:6379> hlen cart:user:1000 (integer) 2 复制代码

删除购物车某件商品

127.0.0.1:6379> hdel cart:user:1000 102 (integer) 1 127.0.0.1:6379> hgetall cart:user:1000 1) "101" 2) "2" 复制代码

四、案例实战

SpringBoot+Redis+Cookies实现高并发的购物车

未登录购物车实体类 @Data public class CookieCart {      //商品id     private Long productId;     //商品数量     private int amount; } 复制代码

登录购物车实体类

@Data public class Cart {     private Long userId;     //商品id     private Long productId;     //商品数量     private int amount; } 复制代码

业务类

    /**      * 未登录      * 添加购物车      */     @PostMapping(value = "/addCart")     public void addCart(CookieCart obj) {         //获取一个Cookies的cardId         String cartId=this.getCookiesCartId();         String key=COOKIE_KEY+cartId;         Boolean hasKey = redisTemplate.opsForHash().getOperations().hasKey(key);         //存在         if(hasKey){             //保存key为购物车,hash的key为商品id,value为数量             this.redisTemplate.opsForHash().put(key, obj.getProductId().toString(),obj.getAmount());         }else{             this.redisTemplate.opsForHash().put(key, obj.getProductId().toString(), obj.getAmount());             this.redisTemplate.expire(key,90, TimeUnit.DAYS);         }     }           /**      * 未登录      * 更改购物车商品数量      */     @PostMapping(value = "/updateCart")     public void updateCart(CookieCart obj) {         String cartId=this.getCookiesCartId();         String key=COOKIE_KEY+cartId;         this.redisTemplate.opsForHash().put(key, obj.getProductId().toString(),obj.getAmount());     }     /**      * 未登录      * 删除购物车商品      */     @PostMapping(value = "/delCart")     public void delCart(Long productId) {         String cartId=this.getCookiesCartId();         String key=COOKIE_KEY+cartId;         this.redisTemplate.opsForHash().delete(key, productId.toString());     }     /**      * 未登录      * 查询某个用户的购物车      */     @PostMapping(value = "/findAll")     public CartPage findAll() {         String cartId=this.getCookiesCartId();         String key=COOKIE_KEY+cartId;         CartPage<CookieCart> cartPage=new CartPage();         //查询该用户购物车的总数         long size=this.redisTemplate.opsForHash().size(key);         cartPage.setCount((int)size);         //查询购物车的所有商品         Map<String,Integer> map= this.redisTemplate.opsForHash().entries(key);         List<CookieCart> cartList=new ArrayList<>();         for (Map.Entry<String,Integer> entry:map.entrySet()){             CookieCart cart=new CookieCart();             cart.setProductId(Long.parseLong(entry.getKey()));             cart.setAmount(entry.getValue());             cartList.add(cart);         }         cartPage.setCartList(cartList);         return cartPage;     }     /**      * 登录      * 合并购物车      * 把cookie中的购物车合并到登录用户的购物车      */     @PostMapping(value = "/mergeCart")     public void mergeCart(Long userId) {         //第一步:提取未登录用户的cookie的购物车数据         String cartId=this.getCookiesCartId();         String keycookie=COOKIE_KEY+cartId;         Map<String,Integer> map= this.redisTemplate.opsForHash().entries(keycookie);         //第二步:把cookie中得购物车合并到登录用户的购物车         String keyuser = "cart:user:" + userId;         this.redisTemplate.opsForHash().putAll(keyuser,map);         //第三步:删除redis未登录的用户cookies的购物车数据         this.redisTemplate.delete(keycookie);         //第四步:删除未登录用户cookies的cartid         Cookie cookie=new Cookie("cartId",null);         cookie.setMaxAge(0);         response.addCookie(cookie);     }               /**      * 获取cookies      */     public  String getCookiesCartId(){         //第一步:先检查cookies是否有cartid         Cookie[] cookies =  request.getCookies();         if(cookies != null){             for(Cookie cookie : cookies){                 if(cookie.getName().equals("cartId")){                     return cookie.getValue();                 }             }         }         //第二步:cookies没有cartid,直接生成全局id,并设置到cookie里面         //生成全局唯一id         long id=this.idGenerator.incrementId();         //设置到cookies         Cookie cookie=new Cookie("cartId",String.valueOf(id));         response.addCookie(cookie);         return id+"";     } } 复制代码

id生成器

@Service public class IdGenerator {     @Autowired     private StringRedisTemplate stringRedisTemplate;     private static final String ID_KEY = "id:generator:cart";     /**      * 生成全局唯一id      */     public Long incrementId() {         long n=this.stringRedisTemplate.opsForValue().increment(ID_KEY);         return n;     } } 复制代码

redis分布式缓存系列


作者:小伙子vae
链接:https://juejin.cn/post/7028759302697386021


文章分类
代码人生
版权声明:本站是系统测试站点,无实际运营。本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 XXXXXXo@163.com 举报,一经查实,本站将立刻删除。
相关推荐