逻辑过期 解决 缓存击穿

什么是逻辑过期

  • 所谓的逻辑过期,类似于逻辑删除,并不是真正意义上的过期,
  • 而是新增一个字段,用来标记key的过期时间,这样能能够避免key过期而被自动删除,这样数据就永不过期了,
  • 从根本上解决因为热点key过期导致的缓存击穿。一般搞活动时,比如抢优惠券,秒杀等场景,请求量比较大就可以使用逻辑过期,等活动一过就手动删除逻辑过期的数据

实现逻辑图

image

代码实现

// 逻辑过期解决缓存击穿
public Shop queryWithLogicalExpire(Long id) {
	// 1. 从redis中查询商铺缓存
	String json = stringRedisTemplate.opsForValue().get(CACHE_SHOP_KEY + id);
	/*
        2. 判断是否在缓存中
        2.1 如果未命中,则返回空,直接失败
         */
	if (StrUtil.isBlank(json)) {
		return null;
	}
	// 2.2 命中,将json反序列化为对象,并判断是否过期
	RedisData redisData = JSONUtil.toBean(json, RedisData.class);
	// 将data转为Shop对象
	JSONObject shopJson = (JSONObject) redisData.getData();
	Shop shop = JSONUtil.toBean(shopJson, Shop.class);
	// 获取过期时间
	LocalDateTime expireTime = redisData.getExpireTime();
	// 3. 判断是否过期
	if (LocalDateTime.now().isBefore(expireTime)) {
		// 3.1 未过期,直接返回商铺信息
		return shop;
	}
	// 4 过期,尝试获取互斥锁
	boolean flag = tryLock(LOCK_SHOP_KEY + id);
	// 4.1 获取到了锁
	if (flag) {
		//  开启独立线程
		CACHE_REBUILD_EXECUTOR.submit(() -> {
			try {
				this.saveShop2Redis(id, 20L);// 此处的expirSeconds应该为物品的活动时间,设置为20只为测试
			} catch (Exception e) {
				throw new RuntimeException(e);
			} finally {
				unlock(LOCK_SHOP_KEY + id);
			}
		});
		//  直接返回商铺信息
		return shop;
	}
	// 4.2 未获取到锁,直接返回商铺信息
	return shop;
}
posted @ 2025-04-09 16:07  kuki'  阅读(61)  评论(0)    收藏  举报