本质:子弹击穿泡沫防护,击穿玻璃。缓存未生效,增数据库查询压力增加。
1、防护(原理):
①将泡沫换成塑料。数据库查询不存在,缓存空值在缓存,例如五分钟内避免重复访问数据库。
②在泡沫后加一层钢筋。过滤器。
1.1实际应用(代码书写)
①防护1:redis空值缓存
@Override
public Result queryById(Long id) {
String key = CACHE_SHOP_KEY + id;
// 1. 从 Redis 中查询商户缓存
String shonJson = stringRedisTemplate.opsForValue().get(key); // 2. 判断是否存在
// 2. 命中真实值,返回数据
if(!StringUtil.isNullOrEmpty(shonJson)){
Shop shop = JSONUtil.toBean(shonJson, Shop.class);
//System.out.println("**************** 我是从缓存中拿的 *****************" );
return Result.ok(shop);
}
// 3. 命中空值(空字符串),返回错误,而不是去查询数据库
if(shonJson != null){
return Result.fail("缓存店铺不存在");
}
// 4. 查询数据库
Shop shop = getById(id);
// 5. 数据库不存在 —— 将空值写入缓存,返回错误
if(shop == null){
// 将空字符串写入 Redis
stringRedisTemplate.opsForValue().set(key, "", 2L, TimeUnit.MINUTES);
return Result.fail("数据库店铺不存在");
}
// 6. 数据库存在 —— 写入 redis ,然后返回
stringRedisTemplate.opsForValue().set(key, JSONUtil.toJsonStr(shop), 30L, TimeUnit.MINUTES);
return Result.ok(shop);
}
参考1:【Redis】缓存穿透概念及其解决方式_redis解决缓存穿透_刘婉晴的博客-CSDN博客
参考2:个人疑点:stringRedisTemplate 是什么(模板,可更改)
StringRedisTemplate和RedisTemplate的区别(二)_valueserializer和hashvalueserializer_ha_lydms的博客-CSDN博客
②防护2:布隆过滤器
参考1:实际引入(redis4.0后使用插件引入可自己查询,这里只体现直接引用)
(Redis使用系列) Springboot 在redis中使用BloomFilter布隆过滤器机制 六_小目标青年的博客-CSDN博客
参考2 :以上引入涉及redis.config书写,其作用
Springboot整合Redis(RedisConfig等工具类编写)_static main的博客-CSDN博客
首先我们要明白RedisConfig中需要包含什么,首先看看我们直接使用RedisTemplate的问题,我们就知道RedisConfig要包含什么了,我们在RedisConfig需要规定好根据不同的查询生成的key,key和value的序列化和反序列化
我们在RedisConfig中配置的自定义方法,最终通过注解引用的就是我们自定义的方法
参考3:涉及知识点,redis安装布隆过滤器涉及的序列化、反序列化意思
其他:具体代码未实际操作过。
首先:代码理解比较简单,先掌握使用redis空值缓存的方式。
其次:因为引入布隆要多一些内容,基本步骤需要引入后,并修改参数值。
-----------
2、这里通过数据走向,来解释”布隆过滤器原理“
从原理发现疑问点:首先明白”缓存穿透“原理及解决方式,我不太理解把内存存在bitmap里,这个步骤如何操作。所以去看了这个参考的代码,明白基本操作
①先把存值进入过滤器->②再通过过滤器校验不存在值
缓存穿透是指用户查询数据,在数据库没有,自然在缓存中也不会有。这样就导致用户查询的时候,在缓存中找不到,每次都要去数据库再查询一遍,然后返回空(相当于进行了两次无用的查询)。这样请求就绕过缓存直接查数据库,这也是经常提的缓存命中率问题。
有很多种方法可以有效地解决缓存穿透问题,最常见的则是采用布隆过滤器,将所有可能存在的数据哈希到一个足够大的bitmap中,一个一定不存在的数据会被这个bitmap拦截掉,从而避免了对底层存储系统的查询压力。另外也有一个更为简单粗暴的方法,如果一个查询返回的数据为空(不管是数据不存在,还是系统故障),我们仍然把这个空结果进行缓存,但它的过期时间会很短,最长不超过五分钟。通过这个直接设置的默认值存放到缓存,这样第二次到缓冲中获取就有值了,而不会继续访问数据库。
疑问解决②:bitmap体现位置(代码)
图片来源参考:(Redis使用系列) Springboot 在redis中使用BloomFilter布隆过滤器机制 六_小目标青年的博客-CSDN博客