缓存穿透产生的原因:
用户请求的数据在缓存中和数据库中都不存在,不断发起这样的请求,给数据库带来巨大压力。
解决方案:
- 缓存空对象
- 布隆过滤
- 增强id的复杂度,避免被猜测id规律
- 做好数据的基础格式校验
- 加强用户权限校验
- 做好热点参数的限流
在这里介绍第一种方式,缓存空对象。操作简单且实用。
-
常见的解决方案:
- 缓存空对象:查询数据库不存在时,返回空值存入redis
- 优点:实现简单,维护方便
- 缺点:额外的内存消耗;可能造成短期的不一致
- 布隆过滤:
- 优点:内存占用少,没有多余key
- 缺点:实现复杂;存在误判可能
- 缓存空对象:查询数据库不存在时,返回空值存入redis
解决缓存穿透问题:
代码展示如下:
//缓存空对象
public Shop queryWithPassThrough(Long id){
// 1、从redis查询商铺缓存
String shopJson = stringRedisTemplate.opsForValue().get(CACHE_SHOP_KEY + id);
// 2、判断是否存在
if(StrUtil.isNotBlank(shopJson)){
// 3、存在,直接返回
Shop shop = JSONUtil.toBean(shopJson, Shop.class);
return shop;
}
//判断命中是否是空值
if(shopJson != null){
//返回一个错误信息
return null;
}
// 4、不存在,根据id查询数据库
Shop shop = getById(id);
// 5、不存在,返回错误
if(shop == null){
// 将null写入redis
stringRedisTemplate.opsForValue().set(CACHE_SHOP_KEY,"",CACHE_NULL_TTL, TimeUnit.MINUTES);
return null;
}
// 6、存在,写入redis
stringRedisTemplate.opsForValue().set(CACHE_SHOP_KEY,JSONUtil.toJsonStr(shop),CACHE_SHOP_TTL, TimeUnit.MINUTES);
// 7、返回
return shop;
}