通过缓存空对象解决缓存穿透问题

1
2
3
4
5
6
7
8
9
10
11
12
@Override
public Result queryById(Long id) {

//通过缓存空值,解决缓存穿透问题
Shop shop = queryWithPassThrough(id);

if(shop==null){
return Result.fail("店铺信息不存在");
}

return Result.ok(shop);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
//缓存空对象解决缓存穿透问题
public Shop queryWithPassThrough(Long id){

//1,从redis中查询商铺缓存

String shopJson = stringRedisTemplate.opsForValue().get(RedisConstants.CACHE_SHOP_KEY + id);

//2,判断是否存在
//2.1 存在直接返回
//在这里判断查到了直接返回,没查到那不是null就是空字符串
if(StrUtil.isNotBlank(shopJson)){

return JSONUtil.toBean(shopJson, Shop.class);
}

//由于我们设置了空对象是空字符串,所以,不是null就说明命中了我们缓存的空对象,可以直接返回错误信息
//等于null的情况下,我们才会到数据库查数据
if(shopJson!=null){

//这里ruturn null 是因为上面函数调用
//如果在一块的话,应该是 return Result.fail("店铺信息不存在");
return null;
}

//2。2 不存在,查询数据库

Shop shop = getById(id);

//数据库不存在直接返回
//这里空对象的标志设为了空字符串 "";
if(shop==null){
stringRedisTemplate.opsForValue().set(RedisConstants.CACHE_SHOP_KEY + id,"",RedisConstants.CACHE_NULL_TTL,TimeUnit.MINUTES);
return null;
}

//存在,写入缓存并返回

stringRedisTemplate.opsForValue().set(RedisConstants.CACHE_SHOP_KEY+ id,JSONUtil.toJsonStr(shop),RedisConstants.CACHE_SHOP_TTL, TimeUnit.MINUTES);

return shop;
}

image-20250307202218456

代码是缓存空对象解决缓存穿透的思路,图中另一个是加了布隆过滤器的解决方案

大体思路

image-20250307202603153