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

代码实现
// 逻辑过期解决缓存击穿
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;
}