学了一段时间的redis了,但是还是感觉有点糊,一边学习一边回顾总结叭
1.缓存穿透
1.1什么是缓存穿透?
答:是指客户端请求的数据在缓存中和数据库中都不存在,这样缓存永远不会生效,这些请求都会打到数据库
2.2解决方案通常有两种
①缓存空对象
优点:实现简单,维护方便
缺点:额外的内存消耗,可能造成短期的不一致
②布隆过滤
优点:内存占用较少,没有多余key
缺点:实现复杂,存在误判可能
3.实现①缓存空对象结局方案:
客户端请求到redis未命中,请求数据库也未命中,服务端就向redis缓存null空值,并设置有效期,使下次请求的不存在数据直接在redis缓存层就被拦截,不会再请求到数据库,减小数据库压力。
如果数据库在有效期内更新之前未存在的数据,会造成短期数据不一致。
4.实现代码
//缓存穿透解决方案
public Shop queryWithPassThrough(Long id){
//1.从redis查询商铺缓存
String shopJson = stringRedisTemplate.opsForValue().get(RedisConstants.CACHE_SHOP_KEY + id);
//2.判断是否为空 isNotBlank判断某字符串是否不为空且长度不为0且不由空白符(whitespace)构成,
if(StrUtil.isNotBlank(shopJson)){
//3.存在直接返回
Shop shop = JSONUtil.toBean(shopJson, Shop.class);
return JSONUtil.toBean(shopJson,shop.getClass());
}
// 如果shopJson 不是null 且为空(上面判断) 证明这就是我们防止缓存穿透设置的空值
if (shopJson!=null){
//返回一个null信息
return null;
}
// 4,不存在根据id查询数据库
Shop shop = getById(id);
// 5.不存在 返回错误
if (shop==null){
//将空值写入redis(防止缓存击穿问题)
//redis set命令就是key value time timetype 字段是我项目需要,不必在意他的含义
stringRedisTemplate.opsForValue().set(RedisConstants.CACHE_SHOP_KEY+ id,"",2L,TimeUnit.MINUTES);
return null;
}
// 6.存在,写入redis 并设置缓存时间有效期为30分钟
stringRedisTemplate.opsForValue().set(RedisConstants.CACHE_SHOP_KEY+ id,JSONUtil.toJsonStr(shop),RedisConstants.CACHE_SHOP_TTL, TimeUnit.MINUTES);
// 7.返回
return shop;
}
最后写一段,有很多问题,根本没有完美的方案,只有最适合的方案,总是要接受一些不完美。