Redis实战篇 | Kyle's Blog (cyborg2077.github.io)
目录
背景
商户查询缓存(根据ID查询)
根据店铺类型查询(List型)
缓存更新策略(保证数据一致性)
案例(利用缓存更新策略)
背景
起初客户端直接向数据库查询数据 添加redis后
商户查询缓存(根据ID查询)
实现业务流程
ShopController
@GetMapping("/{id}")
public Result queryShopById(@PathVariable("id") Long id) {
return shopService.queryById(id);
}
IShopService
public interface IShopService extends IService<Shop> {
Result queryById(Long id);
}
ShopServiceImpl
@Service
public class ShopServiceImpl extends ServiceImpl<ShopMapper, Shop> implements IShopService {
@Resource
public 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.缓存命中,返回
// 将json反序列化为对象
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.数据库存在,写入缓存
stringRedisTemplate.opsForValue().set(key,JSONUtil.toJsonStr(shop),30L, TimeUnit.MINUTES);
// 7.返回
return Result.ok(shop);
}
}
根据店铺类型查询(List型)
Controller
@RestController
@RequestMapping("/shop-type")
public class ShopTypeController {
@Resource
private IShopTypeService typeService;
@GetMapping("list")
public Result queryTypeList() {
return typeService.queryList();
}
}
接口
public interface IShopTypeService extends IService<ShopType> {
Result queryList();
}
实现类
@Service
public class ShopTypeServiceImpl extends ServiceImpl<ShopTypeMapper, ShopType> implements IShopTypeService {
@Resource
public StringRedisTemplate stringRedisTemplate;
@Override
public Result queryList() {
// 1.从redis查询商铺类型
List<String> shopTypes = stringRedisTemplate.opsForList().range(CACHE_SHOP_KEY, 0, -1);
// 2.判断redis是否命中
if(!shopTypes.isEmpty()){
//如果命中则转为ShopType类型返回
List<ShopType> tmp = new ArrayList<>();
for (String types : shopTypes) {
ShopType shopType = JSONUtil.toBean(types, ShopType.class);
tmp.add(shopType);
}
return Result.ok(tmp);
}
//没有命中则查询数据库
List<ShopType> tmp = query().orderByAsc("sort").list();
if(tmp.isEmpty()){
return Result.fail("店铺类型不存在");
}
//3.将数据写入redis
shopTypes.forEach(shopType -> {
stringRedisTemplate.opsForList().rightPush(CACHE_SHOP_KEY,JSONUtil.toJsonStr(shopType));
});
//4.返回
return Result.ok(tmp);
}
}
缓存更新策略(保证数据一致性)
三种更新缓存的策略(保证数据一致性)
我们主要使用主动更新策略
又因为操作数据库和缓存的先后顺序,线程问题;因此需要先修改数据库,再删除缓存,加锁,使用事务。
案例(利用缓存更新策略)
根据id查询店铺时,如果缓存未命中,则查询数据库,将数据库结果写入缓存,并设置超时时间
// 6.数据库存在,写入缓存
stringRedisTemplate.opsForValue().set(key,JSONUtil.toJsonStr(shop), CACHE_SHOP_TTL , TimeUnit.MINUTES);
根据id修改店铺时,先修改数据库,再删除缓存
@Override
@Transactional
public Result update(Shop shop) {
Long id = shop.getId();
if(id == null){
return Result.fail("店铺id不能为空");
}
// 1.更新数据库
updateById(shop);
// 2.删除缓存
stringRedisTemplate.delete(CACHE_SHOP_KEY + id);
return Result.ok();
}