redis做缓存逻辑。本地同步锁加锁解决换错击穿问题。 和分布式锁

@Override
    public Map<String, List<Catelog2Vo>> getCatalogJson() {
        //1.加入缓存逻辑
        String catelogJson = redisTemplate.opsForValue().get("catelogJson");
        if (StringUtils.isEmpty(catelogJson)){
            //2.缓存中没有,从数据库中查询数据
            Map<String, List<Catelog2Vo>> catalogJsonFromDb = getCatalogJsonFromDb();
            //3.查到的数据在放入缓存中  加锁情况下,这段代码可以放入锁中先存缓存在释放锁
            redisTemplate.opsForValue().set("catelogJson", JSON.toJSONString(catalogJsonFromDb),1, TimeUnit.DAYS);
            //返回
            return catalogJsonFromDb;
        }
        // 返回
        return JSON.parseObject(catelogJson,new TypeReference<Map<String,List<Catelog2Vo>>>(){});
    }

2.加锁解决缓存击穿

 /**
     * 从数据库查询并封装数据
     * @return
     */
    public Map<String, List<Catelog2Vo>> getCatalogJsonFromDb() {
        
        //加锁,只要同一把锁,就能锁住,需要这个锁的所有线程
        // synchronized (this){} //锁住当前对象   springBoot所有的组件在容器中都是单利的
        synchronized (this){
            //得到锁以后,我们在去缓存中确定一次,如果没有,在去数据库中查询
            //缓存中取数据
            String catelogJson = redisTemplate.opsForValue().get("catelogJson");
            //如果缓存中不是空的,则直接返回数据
            if (!StringUtils.isEmpty(catelogJson)){
                return JSON.parseObject(catelogJson,new TypeReference<Map<String,List<Catelog2Vo>>>(){});
            }
            //TODO 下面写查询数据逻辑
        }

分布式锁逻辑

 /**
     * 从数据库查询并封装数据 使用Redis分布式锁
     * @return
     */
    public Map<String, List<Catelog2Vo>> getCatalogJsonFromDbRedisLock() {
        //1.占分布式锁。去Redis中占坑     //setIfAbsent 如果Key不存在则保存
        给这个key 设置过期时间  为了解决 死锁问题,设置过期时间
        String uuid = UUID.randomUUID().toString();
        Boolean lock = redisTemplate.opsForValue().setIfAbsent("lock",uuid , 300, TimeUnit.SECONDS);
        //如果占坑成功则返回 true
        if (lock) {
            //加锁成功  //执行业务
            Map<String, List<Catelog2Vo>> dateFromDb;
            try {
                dateFromDb = getDateFromDb();
            } finally {
                //解锁,删除坑位数据
                //  redisTemplate.delete("lock");  //如果锁过期消失,则有可能删除到别人的锁
        //     String lock1 = redisTemplate.opsForValue().get("lock");
        //    //如果创建锁的值和我当前锁的值相同则代表是我自己创建的锁,则删除锁
        //      if (uuid.equals(lock1)){
        //      //删除我自己的锁
        //       redisTemplate.delete("lock");//但是毫秒级的差, 也会出现删除到别人的锁的问题
        //            }
                //使用redis自带了的验证的的脚本
                //如果redis获取的key的值等于我指定的值调用redis 的删除方法把这个key删除掉,如果成功返回1否则返回0
                String script = "if redis.call(\"get\",KEYS[1]) == ARGV[1] then\n" +
                        "    return redis.call(\"del\",KEYS[1])\n" +
                        "else\n" +
                        "    return 0\n" +
                        "end";
                //删除锁
                Integer lock1 = redisTemplate.execute(new DefaultRedisScript<Integer>(
                                script, Integer.class)
                        , Arrays.asList("lock")
                        , uuid);
            }

            return dateFromDb;
        } else {
            //加锁失败...重试
            //重试次数太高 休眠100ms重试
            return getCatalogJsonFromDbRedisLock(); //自旋的方式
        }

    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值