根据id查询商品:
添加redis缓存(增强读写功能)步骤
1.从redis中获取商品信息,判断信息是否存在
2.若存在则从redis中获取,不存在则直接查询数据库
3.若数据库中不存在则返回错误信息
4.若数据库中存在则同同样将信息存入redis中
controller层
@GetMapping("/{id}")
public Result queryShopById(@PathVariable("id") Long id) {
return shopService.queryById(id);
}
service层
@Resource
private StringRedisTemplate stringRedisTemplate;
@Override
public Result queryById(Long id) {
String key=CACHE_SHOP_KEY+id;
//从redis查询商品缓存
String shopJson = stringRedisTemplate.opsForValue().get(key);
//判断是否命中,若命中
if(StrUtil.isNotBlank(shopJson)){
Shop shop = JSONUtil.toBean(shopJson, Shop.class);
return Result.ok(shop);
}
//判断命中是否为空值
if(shopJson!=null){
//返回一个错误信息
return Result.fail("店铺不存在");
}
//若不存在,查询数据库
Shop shop = getById(id);
if(shop==null){
//将空值写入redis
stringRedisTemplate.opsForValue().set(key,"",CACHE_NULL_TTL,TimeUnit.MINUTES);
return Result.fail("店铺不存在");
}
//存入redis
stringRedisTemplate.opsForValue().set(key,JSONUtil.toJsonStr(shop),CACHE_SHOP_TTL, TimeUnit.MINUTES);
return Result.ok(shop);
}
有可能发生数据库和redis中信息存储不一致的情况,即缓存更新问题
对于低一致性的需求:可以使用内存淘汰,例如商品店铺的查询缓存
对于高一致性的需求:使用主动更新,并以超时剔除为兜底方案,例如商品详情查询的缓存
然后应该先操作数据库,再删除缓存
查询店铺
controller类
@GetMapping("/{id}")
public Result queryShopById(@PathVariable("id") Long id) {
return shopService.queryById(id);
}
service类
@Resource
private StringRedisTemplate stringRedisTemplate;
@Override
public Result queryTypeList() {
String key=CACHE_SHOP_TYPE_KEY;
//从redis中读取缓存
String type = stringRedisTemplate.opsForValue().get(key);
//判断是否命中缓存
if(StrUtil.isNotBlank(type)){
//若存在
List<ShopType> list = JSONUtil.toList(type, ShopType.class);
return Result.ok(list);
}
//若不存在,查找数据库
List<ShopType> shopTypes = query().orderByAsc("sort").list();
if(shopTypes==null){
return Result.fail("分类不存在!");
}
//存入redis
stringRedisTemplate.opsForValue().set(key,JSONUtil.toJsonStr(shopTypes));
return Result.ok(shopTypes);
}
还需考虑缓存穿透问题
解决方案
1.从redis中获取信息,判断信息是否存在(再判断是否为空值)
2.若存在则从redis中获取,不存在则直接查询数据库
3.若数据库中不存在则设置为空值存入redis并设置有效时长
4.若数据库中存在则同同样将信息存入redis中
缓存雪崩