redis一些问题的解决方案

1.缓存空值解决缓存穿透

1.1什么是缓存穿透

1.2解决方案

1.3代码实现


  //缓存穿透解决方案
    public Shop queryWithPassThough(Long id){
        //从redis查询商铺缓存
        String shopJson = stringRedisTemplate.opsForValue().get(CACHE_SHOP_KEY + id);

        //判断是否存在
        if (StrUtil.isNotBlank(shopJson)) {
            //存在直接返回
            Shop shop = JSONUtil.toBean(shopJson, Shop.class);
            return shop;
        }
        //判断是否命中空值 //防止缓存穿透
        if (shopJson !=null){//上面的isNotBlank方法会将空字符串或者null传递到下面,如果不是null那么就是空字符串
            return null;
        }
        //不存在根据id查询
        Shop shop = getById(id);

        //不存在返回错误
        if (shop==null){
            //将空值写入redis //防止缓存穿透
            stringRedisTemplate.opsForValue().set(CACHE_SHOP_KEY+id,"",CACHE_NULL_TTL,TimeUnit.MINUTES);
            return null;
        }
        //存在,写入redis
        stringRedisTemplate.opsForValue().set(CACHE_SHOP_KEY+id,JSONUtil.toJsonStr(shop),CACHE_SHOP_TTL, TimeUnit.MINUTES);

        return shop;
    }

2.缓存雪崩及其解决方案

3.解决缓存击穿

3.1什么是缓存击穿

3.2解决方案

3.3代码实现

3.3.1模拟互斥锁解决


private boolean tryLocal(String key){
        Boolean flag = stringRedisTemplate.opsForValue().setIfAbsent(key, "1", 10, TimeUnit.SECONDS);
        return BooleanUtil.isTrue(flag);//防止拆箱。出现空指针
    }

    private void unLocal(String key){
        stringRedisTemplate.delete(key);
    }
//缓存击穿解决方案
    public Shop queryWithMutex(Long id){
        //从redis查询商铺缓存
        String shopJson = stringRedisTemplate.opsForValue().get(CACHE_SHOP_KEY + id);

        //判断是否存在
        if (StrUtil.isNotBlank(shopJson)) {
            //存在直接返回
            return JSONUtil.toBean(shopJson, Shop.class);
        }
        //判断是否命中空值 //防止缓存穿透
        if (shopJson !=null){//上面的isNotBlank方法会将空字符串或者null传递到下面,如果不是null那么就是空字符串
            return null;
        }
        //实现缓存重建
        //获取互斥锁
        String localKey=LOCK_SHOP_KEY+id;
        Shop shop=null;
        try {
            boolean isLocal = tryLocal(localKey);
            //判断是否获取成功
            if (!isLocal){
                //失败,则休眠并重试
                Thread.sleep(50);
                return queryWithMutex(id);
            }
            //成功,根据id查询
            //再检测redis缓存是否存在,DoubleCheck
            //??
            shop = getById(id);

            //不存在返回错误
            if (shop==null){
                //将空值写入redis
                stringRedisTemplate.opsForValue().set(CACHE_SHOP_KEY+id,"",CACHE_NULL_TTL,TimeUnit.MINUTES);
                return null;
            }
            //存在,写入redis
            stringRedisTemplate.opsForValue().set(CACHE_SHOP_KEY+id,JSONUtil.toJsonStr(shop),CACHE_SHOP_TTL, TimeUnit.MINUTES);
        }catch (InterruptedException e){
            throw new RuntimeException(e);
        }finally {
            //释放互斥锁
            unLocal(localKey);
        }

        //返回
        return shop;
    }

3.3.2逻辑过期解决


 private static final ExecutorService CACHE_REBUILD_EXECUTOR= Executors.newFixedThreadPool(10);//线程池

    //缓存击穿解决方案--逻辑过期
    public Shop queryWithLogicalExpire(Long id){
        //从redis查询商铺缓存
        String shopJson = stringRedisTemplate.opsForValue().get(CACHE_SHOP_KEY + id);

        //判断是否存在
        if (StrUtil.isBlank(shopJson)) {
            //不存在存在直接返回空
            return null;
        }
        //命中,先把json反序列化为对象
        RedisData redisData = JSONUtil.toBean(shopJson, RedisData.class);
        Shop shop = JSONUtil.toBean((JSONObject) redisData.getData(), Shop.class);
        LocalDateTime expireTime = redisData.getExpireTime();
        //判断是否过期
        if (expireTime.isAfter(LocalDateTime.now())){
            //未过期,直接返回店铺信息
            return shop;
        }
        //过期,需要缓存重建
        //缓存重建
        //获取互斥锁
        String lockKey=LOCK_SHOP_KEY+id;
        boolean isLock = tryLocal(lockKey);
        //是否获取成功
        if (isLock){
            //成功,开启独立线程,实现缓存重建
            CACHE_REBUILD_EXECUTOR.submit(()->{
                //重建
                try {
                    saveShop2Redis(id,20L);
                }catch (Exception e){
                    throw new RuntimeException(e);
                }finally {
                    //释放锁
                    unLocal(lockKey);
                }


            });
        }

        //失败,返回过期商铺信息
        return shop;
    }

内容来自黑马程序员-Redis入门到实战

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值