缓存穿透
缓存穿透是指客户端请求的数据在缓存中和数据库中都不存在,这样缓存永远不会生效,这些请求都会被打倒数据库上。
即这个数据根本不存在,如果有一个坏人,启用很多个线程,一直对这个不存在的数据发送请求 ,那么请求就会一直被打到数据库上,很容易将数据库打崩。
两种解决方案
也可以增加id的复杂度,避免被猜测id规律
做好数据的基础格式校验
加强用户的权限校验
对热点参数做限流
缓存空对象
缓存一个空对象在Redis中,优点是实现简单,维护方便,缺点是额外的内存消耗,因为缓存了一些瞎编的id对应的空对象,但是可以通过给对象设置TTL解决,也可能造成短期的数据不一致,如果此时真的存入了一个瞎编的id对应的对象,那么此时Redis中就缓存了一个空对象,此时用户去查询数据,明明数据库已经有了对应的对象,但是用户得到的依然是一个空对象,这个也可以通过将TTL设置的时间短一些来解决。
布隆过滤器
不存在真的不存在,存在不一定存在,并非百分百准确,有一定的穿透风险。
内存占用较少,但是实现复杂,存在误判可能
下面采用缓存空对象的方式解决缓存穿透
最终代码如下
public Result queryById(Long id) {
String key = CACHE_SHOP_KEY + id;
String shopJson = stringRedisTemplate.opsForValue().get(key);
Shop shop = null;
if (StrUtil.isNotBlank(shopJson)) {
shop = JSONUtil.toBean(shopJson, Shop.class);
} else {
// 命中的是否是空值,即是否为""
if (shopJson != null) {
return Result.fail("店铺信息不存在");
}
shop = getById(id);
if (shop == null) {
// 写入空值
stringRedisTemplate.opsForValue().set(key, "", CACHE_NULL_TTL, TimeUnit.MINUTES);
return Result.fail("店铺不存在!");
}
stringRedisTemplate.opsForValue().set(key, JSONUtil.toJsonStr(shop), CACHE_SHOP_TTL, TimeUnit.MINUTES);
}
return Result.ok(shop);
}