使用逻辑过期机制解决缓存击穿问题

逻辑过期是一种缓存策略,通过在缓存中存储数据的同时,记录一个过期时间。在缓存未过期时,直接返回缓存数据;在缓存过期后,即使缓存中的数据过期,也返回旧数据,同时异步刷新缓存。这种机制保证了缓存的高可用性,并减少了对数据库的直接访问。

public Shop queryWithLogicalExpire(Long id) {
    // 1. 从redis中查询商铺缓存
    String json = stringRedisTemplate.opsForValue().get(CACHE_SHOP_KEY + id);
    // 2. 如果未命中,则返回空
    if (StrUtil.isBlank(json)) {
        return null;
    }
    // 3. 命中,将json反序列化为对象
    RedisData redisData = JSONUtil.toBean(json, RedisData.class);
    // 3.1 将data转为Shop对象
    JSONObject shopJson = (JSONObject) redisData.getData();
    Shop shop = JSONUtil.toBean(shopJson, Shop.class);
    // 3.2 获取过期时间
    LocalDateTime expireTime = redisData.getExpireTime();
    // 4. 判断是否过期
    if (LocalDateTime.now().isBefore(expireTime)) {
        // 5. 未过期,直接返回商铺信息
        return shop;
    }
    // 6. 过期,尝试获取互斥锁
    boolean flag = tryLock(LOCK_SHOP_KEY + id);
    // 7. 获取到了锁
    if (flag) {
        // 8. 开启独立线程
        CACHE_REBUILD_EXECUTOR.submit(() -> {
            try {
                this.saveShop2Redis(id, LOCK_SHOP_TTL);
            } catch (Exception e) {
                throw new RuntimeException(e);
            } finally {
                unlock(LOCK_SHOP_KEY + id);
            }
        });
        // 9. 直接返回商铺信息
        return shop;
    }
    // 10. 未获取到锁,直接返回商铺信息
    return shop;
}

public void saveShop2Redis(Long id, Long expireSeconds) {
    Shop shop = getById(id);
    RedisData redisData = new RedisData();
    redisData.setData(shop);
    redisData.setExpireTime(LocalDateTime.now().plusSeconds(expireSeconds));
    stringRedisTemplate.opsForValue().set(CACHE_SHOP_KEY + id, JSONUtil.toJsonStr(redisData));
}

优点

  1. 高可用性:即使缓存过期,也可以快速返回旧数据,提升系统的响应速度。
  2. 减少数据库压力:通过异步刷新缓存,减少对数据库的直接访问,避免数据库压力骤增。
  • 6
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值