购物车的redis数据结构使用hashmap效率会更高(1、同步缓存 2、查询缓存)

一、回忆一下该项目之前所使用的数据结构

1、 有用到redis缓存技术的是访问商品的详情页面前先访问redis(kv结构)。
2、 有用到hashMap结构的是商品的详情页面制作spu下其他sku商品为哈希表(hash结构)。

二、这里购物车的缓存使用hashmap数据结构

在这里插入图片描述
1、 存储的是购物车集合
2、 键:用户id
3、 购物车里的某个sku商品的更新
4、 使用哪个数据结构较好?kv和hashmap
×如果使用kv结构,取出json,转换为集合,集合再遍历出对象,修改对象,再放回集合,转为json,最后放回缓存。(较麻烦)
√使用hash结构存储(方便修改和查询购物车某个对象数据)

代码实现(注意这里有一个重大bug,同步缓存hmset进去之前,要先删除之前的缓存!!!!):

//同步到Redis缓存中
@Override
public void flushCartCache(String memberId) {

    OmsCartItem omsCartItem = new OmsCartItem();
    omsCartItem.setMemberId(memberId);
    List<OmsCartItem> omsCartItemList = omsCartItemMapper.select(omsCartItem);   //查询某个用户memberId的购物车

    Jedis jedis = redisUtil.getJedis();

    HashMap<String,String> hashMap = new HashMap<>();

    for (OmsCartItem cartItem : omsCartItemList) {        //遍历该购物车列表

//在购物车当中用户点击商品的选中状态,需要查询缓存,但是缓存当中的总价格没有计算,这里在同步之前,就计算总价格!!!bug!!!
cartItem.setTotalPrice(cartItem.getPrice().multiply(cartItem.getQuantity()));

        hashMap.put(cartItem.getProductSkuId(), JSON.toJSONString(cartItem));   //把skuId作为k,购物车对象作为v
    }


    jedis.del("user:"+memberId+":cart");  //重大的bug!!!要先删除原本的缓存,再同步新的缓存!!!
    jedis.hmset("user:"+memberId+":cart",hashMap);



    jedis.close();
}

5、这里的实体类出现了bug,商品的数量如果使用int类型,会导致tk通用mapping封装不上这个字段,无法添加到数据库。
所以这里的实体类要把int类型改成BigDecimal
在这里插入图片描述
web层还是int类型,需要new BigDecimal()对象接收quantity才行
在这里插入图片描述

6、启动类拉到gmall包下,否则会扫描不到redisUtil工具,不要忘了加注解扫描mapper包

@MapperScan(basePackages = "com.atguigu.gmall.cart.service.mapper")

在这里插入图片描述

7、redis使用哈希map数据结构的所有方法

redis-cli -h 172.25.0.11 -p 6379   //连接redis
keys *   //查询所有key

hvals user:1:cart     查询(所有)用户id为1的所有购物车内容
hget user:1:cart 127  查询(一个)用户id为1的购物车的(一个)sku商品id为127的商品
hset user:1:cart 127 value  添加(一个)skuId为127及其其他所有(多个)value值到用户id为1的用户

del user:1:cart 删除用户id为1的所有购物车信息

三、既然有同步缓存,那当然还有查询缓存,在service服务层,类似之前做的商品详细页面添加的缓存技术一样,都是为了保护数据库的!代码如下:

//用户已经登录,查询该用户的db的购物车,此操作为用户最为频繁的操作,需要添加中间件缓存服务器
@Override
public List<OmsCartItem> cartList(String memberId) {

    Jedis jedis = null;
    List<OmsCartItem> omsCartItemList = new ArrayList<>();

    try{
        jedis = redisUtil.getJedis();
        String member = "user:"+memberId+":cart";
        List<String> hvals = jedis.hvals(member);

        if(hvals.size()!=0){  //查询缓存,不为空,即存储了该用户的数据
            for (String hval : hvals) {
                OmsCartItem omsCartItem = JSON.parseObject(hval, OmsCartItem.class);
                omsCartItemList.add(omsCartItem);
            }

        }else {

            String token = UUID.randomUUID().toString();
            String lock = jedis.set(member, token, "nx", "px", 10 * 1000);    //防止缓存击穿
            if(StringUtils.isNotBlank(lock) && lock.equals("OK")){

                //操作数据库,需要被保护
                OmsCartItem omsCartItem = new OmsCartItem();
                omsCartItem.setMemberId(memberId);
                omsCartItemList = omsCartItemMapper.select(omsCartItem);

                HashMap<String,String> hashMap = new HashMap<>();

                if(omsCartItemList.size()==0){            //查询数据库获得的是空值
                    jedis.setex(member,2*60,JSON.toJSONString(""));           //防止缓存穿透

                }else {      //数据库中有值,同步到缓存当中

                    for (OmsCartItem cartItem : omsCartItemList) {        //遍历该购物车列表
                        hashMap.put(cartItem.getProductSkuId(), JSON.toJSONString(cartItem));   //把skuId作为k,购物车对象作为v
                    }
                    jedis.hmset(member,hashMap);

                }

                String script ="if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
                jedis.eval(script, Collections.singletonList(member),Collections.singletonList(token));    //使用脚本删除锁,确保原子性执行,避免删除别人的锁

            }else {
                return cartList(memberId);
            }

        }

    }catch (Exception e){
        e.printStackTrace();
    }finally {
        jedis.close();
    }



    return omsCartItemList;
}
  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
收藏夹和购物车系统的实现  收藏夹子系统 (1) 【收藏指定图书】能收藏一本图书,并记录收藏日期(某年某月某日,如2016-12-12。所有日期都采用人工定义方式输入,不取机器日期)。图书的信息包括图书号(是唯一的)、书名、作者、出版社、出版日期、价格。 (2) 【查询指定图书】能按照图书号查询显示收藏夹中图书的相关信息(也可以扩展功能为按照书名、作者、出版社、出版日期、指定价格大小范围查询显示收藏夹中图书的相关信息)。 (3) 【按日期显示所有图书】能按照收藏日期的先后显示输出所收藏的所有图书的相关信息。 (4) 【移出收藏夹】可以把不想收藏的某一本指定图书号的图书直接移出收藏夹。 (5) 【加入购物车】将收藏夹中的某一本指定图书号的图书加入到购物车。 (6) 【按价格显示所有图书】能按照价格的大小显示输出收藏夹中的所有图书的相关信息。  购物车子系统 (1) 【直接加入购物车】把准备购买的一本图书直接加入购物车,同时记录加入购物车的日期。图书的信息包括图书号(是唯一的)、书名、作者、出版社、出版日期、价格、购买数量、购买金额(自动计算)。 (2) 【查询指定图书】能按照图书号查询显示购物车中准备购买的图书的相关信息(也可以扩展功能为按照书名、作者、出版社、出版日期、指定价格大小范围查询显示购物车中图书的相关信息)。 (3) 【修改购买数量】可以修改购物车中准备购买的某一本指定图书号的图书的数量,同时自动计算修改购买金额(购买金额=购买数量*价格)。 (4) 【删除指定图书并移到收藏夹】把购物车中的某一本指定图书号的图书删除并移到收藏夹。 (5) 【直接删除指定图书】可以把不想购买的某一本指定图书号的图书从购物车中删除。 (6) 【按图书号显示所有图书】把购物车中所有图书按照图书号列出每一本图书的图书号、书名、作者、出版社、出版日期、价格、购买数量、购买金额,最后列出总共有多少本图书、总金额是多少。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值