回顾上文
上文已经解释了Redis的更新策略为主动更新,并以超时剔除来兜底的方案,而主动更新的实施方案则是采取先操作数据库,再删除缓存的方案,可以最大程度的避免操作后数据不一致的问题。
案例解析
给查询商铺的缓存添加超时剔除以及更新商铺时主动更新:
- 根据id查询店铺时,如果缓存未命中,则查询数据库,将数据库结果写入缓存,并设置超时时间
- 根据id修改店铺时,先修改数据库,再删除缓存
首先是redis的写入操作,在写入Redis时设置超时时间:
public Result queryById(Long id) {
String key = "cache:shop:" + id;
// 1.从redis查询商铺缓存
String shopJson = stringRedisTemplate.opsForValue().get(key);
// 2.判断是否存在
if (StrUtil.isNotBlank(shopJson)) {
// 3.存在,转成Java对象,直接返回
Shop shop = JSONUtil.toBean(shopJson, Shop.class);
return Result.ok(shop);
}
// 4.不存在,根据id查询数据库
Shop shop = getById(id);
// 5.不存在,返回错误
if (shop == null) {
return Result.fail("店铺不存在");
}
// 6.存在,写入redis。在此处设置超时剔除
stringRedisTemplate.opsForValue()
.set(key, JSONUtil.toJsonStr(shop),30L, TimeUnit.MINUTES);
// 7.返回
return Result.ok(shop);
}
接下来对更新店铺的逻辑进行修改,先修改数据库再删除缓存:
先找到更新商铺的接口
/**
* 更新商铺信息
* @param shop 商铺数据
* @return 无
*/
@PutMapping
public Result updateShop(@RequestBody Shop shop) {
// 写入数据库
updateById(shop)
return Result.ok();
}
这里使用的是MP的updateById方法,将这里的方法改成自定义的update方法
/**
* 更新商铺信息
* @param shop 商铺数据
* @return 无
*/
@PutMapping
public Result updateShop(@RequestBody Shop shop) {
// 写入数据库
return shopService.update(shop);
}
接下来来到serviceImpl层实现该方法:
为了整个方法能够统一的完成,添加@Transactional注解开启事务
@Override
@Transactional
public Result update(Shop shop) {
// 1.更新数据库
Long id = shop.getId();
if (id == null) {
return Result.fail("店铺id不能为空");
}
updateById(shop);
// 2.删除缓存
stringRedisTemplate.delete("cache:shop:" + id);
return Result.ok();
}
到此成功完成对商铺更新添加超时剔除和主动更新。
测试功能
首先测试一下超时剔除的功能:
进入到店铺页面
来到redis客户端查看缓存的有效期,发现有效期刷新了
测试通过
再测试一下主动更新的功能:
打开apifox或postman,测试接口如下:http://localhost:8081/shop PUT
测试数据如下:
{
"area": "大关",
"openHours": "10:00-22:00",
"sold": 4215,
"address": "金华路锦昌文化苑29号",
"comments": 3035,
"avgPrice": 80,
"score": 37,
"name": "102茶餐厅",
"typeId": 1,
"id": 1
}
更新店铺数据后来到redis客户端查看,发现该条缓存已被删除:
再次来到黑马店铺刷新店铺信息,触发查询动作,查看redis客户端,最新的数据成功缓存到redis
功能测试通过