什么是缓存穿透?
缓存穿透是指客户端请求的数据在缓存和数据库中都不存在,这样缓存永远不会生效,这些请求都会打到数据库。如果这些不存在的数据被大量恶意的访问,就会增加数据库和服务器的压力。
如何解决缓存穿透
常见的解决方案有两种:
缓存空对象
- 优点:实现简单,维护方便
- 缺点:
1、额外的内存消耗
2、可能造成短期缓存和数据库数据不一致的情况
布隆过滤
- 优点:内存占用较少,没有多余key
- 缺点:
1、实现复杂
2、存在误判可能:布隆过滤是通过将每个插入数据库的值转化成对应的哈希值,在把哈希值转成对应的二进制,并在对应的二进制位上标记该数据是否存在,因存在哈希冲突,故可能出现误判,即布隆判断数据存在,其不一定存在
缓存空对象的实现示例
@Service
public class ShopServiceImpl extends ServiceImpl<ShopMapper, Shop> implements IShopService {
@Resource
private StringRedisTemplate stringRedisTemplate;
@Override
public Result queryById(Long id) {
String key = CACHE_SHOP_KEY + id;
//1.从redis查询商铺缓存
String shopJson = stringRedisTemplate.opsForValue().get(key);
//2.判断是否存在
if (StrUtil.isNotBlank(shopJson)) {
//3.存在 直接返回
Shop shop = JSONUtil.toBean(shopJson, Shop.class);
return Result.ok(shop);
}
//判断命中是否是空值
if (shopJson != null){
return Result.fail("店铺不存在");
}
//4.不存在 根据id查询数据库
Shop shop = getById(id);
//5.数据库不存在 返回错误
if (shop == null) {
//解决缓存穿透1
//将空值写入redis
stringRedisTemplate.opsForValue().set(key,"",CACHE_NULL_TTL, TimeUnit.MINUTES);
return Result.fail("店铺不存在");
}
//6.存在 写入redis
stringRedisTemplate.opsForValue().set(key,JSONUtil.toJsonStr(shop),CACHE_SHOP_TTL, TimeUnit.MINUTES);
//7.返回
return Result.ok(shop);
}
}