解决redis缓存穿透、缓存击穿问题

缓存穿透

image

解决思路:

image

    public Result queryWithPassThrough(Long id) {
        String key = CACHE_SHOP_KEY + id;
        String shopJson = stringRedisTemplate.opsForValue().get(key);
        if (shopJson != null && !"".equals(shopJson)) { //不等于null,且不等于""
            Shop shop = JSONUtil.toBean(shopJson, Shop.class);
            return Result.ok(shop);
        }
        if (shopJson!=null){    //缓存的是""
            return Result.fail("店铺不存在");
        }

        Shop shop = getById(id);
        if (shop == null){
            stringRedisTemplate.opsForValue().set(key,"",2L,TimeUnit.MINUTES);
            return Result.fail("店铺不存在");
        }
        stringRedisTemplate.opsForValue().set(key,JSONUtil.toJsonStr(shop));
        return Result.ok(shop);
    }

image

缓存雪崩

image

缓存击穿

image

image

image

解决思路

image

    public Result queryWithMutex(Long id) {
        String key = CACHE_SHOP_KEY + id;
        Shop shop = null;
        String shopJson = stringRedisTemplate.opsForValue().get(key);
        if (shopJson != null && !"".equals(shopJson)) { //不等于null,且不等于""
            shop = JSONUtil.toBean(shopJson, Shop.class);
            return Result.ok(shop);
        }
        if (shopJson!=null){    //缓存的是""
            return Result.fail("店铺不存在");
        }

        //未命中redis缓存
        String lockKey = "lock:shop:"+id;

        try {
            boolean lock = tryLock(lockKey);
            if (!lock){
                Thread.sleep(10);
                return queryWithMutex(id);
            }

            shopJson = stringRedisTemplate.opsForValue().get(key);  //双重校验
            if (shopJson == null){
                shop = getById(id);
                Thread.sleep(200);  //模拟查询数据库重建业务
                if (shop == null){
                    stringRedisTemplate.opsForValue().set(key,"",2L,TimeUnit.MINUTES);
                    return Result.fail("店铺不存在");
                }
                stringRedisTemplate.opsForValue().set(key,JSONUtil.toJsonStr(shop));
            }
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        } finally {
            unLock(lockKey);
        }

        return Result.ok(shop);
    }


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

    private void unLock(String key){
        stringRedisTemplate.delete(key);
    }

image

posted @ 2024-02-28 21:49  ︶ㄣ演戲ㄣ  阅读(11)  评论(0)    收藏  举报