目录
在开发高并发的应用时,频繁访问数据库会导致性能瓶颈。基于上一篇博客的代码,我们可以通过优化来解决缓存穿透的问题。
缓存穿透问题
缓存穿透是指请求的数据在缓存和数据库中都不存在,每次请求都会直接访问数据库,从而失去了缓存的意义,导致数据库负载过高。
优化后的代码示例
下面是优化后的代码,解决了缓存穿透的问题:
@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) {
// 将空值写入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);
}
}
代码主要过程
-
从Redis查询缓存
首先从Redis中查询缓存数据。 -
判断缓存是否存在
判断缓存中是否存在对应的商铺数据。如果存在,直接转换为Shop对象并返回。这里存在是指键和值都不为空。 -
处理缓存穿透
如果缓存中的数据为空字符串(即shopJson != null
但StrUtil.isNotBlank(shopJson)
为false),表示之前数据库中没有该商铺信息,为了防止缓存穿透,返回错误信息。if (shopJson != null) { return Result.fail("店铺不存在"); }
-
查询数据库
如果Redis中没有缓存该商铺信息,则需要从数据库中查询。通过getById(id)
方法查询数据库中的商铺数据。 -
将空值写入Redis
如果数据库中也不存在该商铺信息,将一个空字符串写入Redis,并设置过期时间,防止缓存穿透。if (shop == null) { stringRedisTemplate.opsForValue().set(key, "", CACHE_NULL_TTL, TimeUnit.MINUTES); return Result.fail("店铺不存在"); }
-
将数据写入Redis
如果数据库中存在该商铺信息,则将该信息转换为JSON字符串后写入Redis缓存,同样设置缓存过期时间。stringRedisTemplate.opsForValue().set(key, JSONUtil.toJsonStr(shop), CACHE_SHOP_TTL, TimeUnit.MINUTES);
-
返回数据
最后,将查询到的商铺数据返回。
通过以上优化,我们可以有效地防止缓存穿透问题,减少数据库的压力,提高系统的性能和稳定性。希望本文对你在项目中解决缓存穿透问题有所帮助。