缓存击穿问题也叫热点key问题,就是一个被高并发访问并且缓存重建业务比较复杂的key突然失效了,无数的请求访问会在瞬间给数据库带来巨大的冲击

常见的解决方案有两种:
互斥锁(高并发时性能较差)

逻辑过期


基于互斥锁方式解决缓存基穿问题

//解决缓存击穿问题
public Shop queryWithMutex(Long id){
//1.直接从redis中查询商铺id
String json = stringRedisTemplate.opsForValue().get(CACHE_SHOP_KEY + id);
//互斥锁的key
String isKey = "lock:shop:" + id;
Shop shop = null;
try {
//2.判断redis中是否有
if (StringUtils.isNotBlank(json)) {
//3.如果有直接返回查询结果
//将json格式转换为对象
shop = JSONUtil.toBean(json, Shop.class);
return shop;
}
if (json != null) {//!=null 就为""
//返回一个错误
return null;
}
//解决缓存击穿
//4.获取互斥锁
boolean flag = tryLock(isKey);
//4.1判断锁是否获取成功
if (!flag) {
//4.2休眠
Thread.sleep(50);
//4.3未获取 递归调用
return queryWithMutex(id);
}
// 4.4 成功 根据id查询数据库
shop = this.getById(id);
//5.将商铺信息写入redis中
//将sp转化为json格式
String shopJson = JSONUtil.toJsonStr(shop);
stringRedisTemplate.opsForValue().set(CACHE_SHOP_KEY + id, shopJson, CACHE_SHOP_TTL, TimeUnit.MINUTES);
} catch (InterruptedException e) {
throw new RuntimeException(e);
} finally {
//6.释放锁
unlock(isKey);
}
//7.返回数据
return shop;
}
//模拟获取锁
private boolean tryLock(String key){
Boolean flage = stringRedisTemplate.opsForValue().setIfAbsent(key, "1", 10, TimeUnit.SECONDS);
return BooleanUtil.isTrue(flage);
}
//释放锁
private void unlock(String key){
stringRedisTemplate.delete(key);
}
通过redis中
Redis Setnx 命令,命令在指定的 key 不存在时,为 key 设置指定的值。来模拟上锁
通过delete模拟释放锁 来达到应有的效果


















