缓存一致性问题三种解决方案附上代码
「这是我参与2022首次更文挑战的第8天,活动详情查看:2022首次更文挑战」。
概述
缓存一致性问题也是使用缓存中比较经典的问题之一。使用缓存,涉及数据库和缓存两部分数据的维护,既然是两个组件的数据,那么必然有数据一致性问题。常用的解决方案有三种,分别是设置过期时间,先更新数据库,再删缓存,先删缓存,再更新数据库。 吗,
设置过期时间
代码示例
1.查询数据
@RequestMapping("/cache/db/{userId}")
@GetMapping
public User getUser(@PathVariable Integer userId){
//查询缓存
String str = stringRedisTemplate.opsForValue().get("user:"+userId);
if(str==null){
//查询数据库
User user = userMapper.selectById(userId);
//设置缓存
stringRedisTemplate.opsForValue().set("user:"+userId,JSONUtil.toJsonStr(user),Duration.ofSeconds(100L));
return user;
}else {
return JSONUtil.toBean(str,User.class);
}
}
2.更新数据
@RequestMapping("/cache/db")
@PutMapping
public String update(@RequestBody User user){
//更新数据,直接等待缓存过期即可查询到真实数据
userMapper.updateById(user);
return "success";
}
优缺点
优点:编码简单实用,代码复杂度低,能够实现缓存和数据库最终一致。 缺点:时效性差,必须要等待缓存过期,才能看到真实数据,适合对数据要求实时性不高的场景。
先更新数据库,再删缓存(推荐)
代码示例
@RequestMapping("/cache/db/delete")
@PutMapping
public String updateDelete(@RequestBody User user){
//更新数据,直接等待缓存过期即可查询到真实数据
userMapper.updateById(user);
//删除缓存
stringRedisTemplate.delete("user:"+user.getId());
return "success";
}
优缺点
优点:编码也简单实用,代码复杂度低,能够实现缓存一致性,并且实时性高。
缺点: 1.实时性高,但是依然不是强一致性,删除缓存之前存在旧数据可能
2.假设网络抖动,缓存删除失败,依然和方案1一样的实时性不高,但是可以做一些 重试的补偿措施。
先删缓存,再更新数据库
代码示例
@RequestMapping("/cache/db/double/delay/delete")
@PutMapping
public String updateDoubleDelayDelete(@RequestBody User user){
//第一次删除
stringRedisTemplate.delete("user:"+user.getId());
//更新数据,直接等待缓存过期即可查询到真实数据
userMapper.updateById(user);
//第二次延迟删除缓存
executorService.submit(()->{
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
stringRedisTemplate.delete("user:"+user.getId());
});
return "success";
}
优缺点
优点: 1.能够实现缓存一致性,也做了缓存删除,实时性也较高
2.代码第一步就删缓存,如果这个时候没有线程查询数据,直到更新完数据库才查询,那么会触发其它查询线程查询数据库,得到最新数据,实时性要更高一点(相比方案2)
缺点: 1.代码复杂度比较高,使用了异步做延迟二次删除缓存
2.代码第一步就删缓存,如果紧接着有其它线程查询,那么这次删除缓存意义不大,依然缓存被填充了旧数据,而且等延迟双删,还需要延迟时间后才能看到新数据
3.假设网络抖动,缓存延迟删除失败,依然和方案1一样的实时性不高,但是可以做一些 重试的补偿措施
总结
1.三种方案都是最终一致性
2.方案一实时性差一点,方案二和方案三实时性差不多,但是我比较推荐方案二,方案二代码复杂度低,方案删先删缓存还是无法做到强一致性,所以推荐方案二编码简单一些
3.如果真的需要强一致性,那么推荐加事务,这样就能满足完全强一致性,除非业务要求一致性特别高情况。
转载自:https://juejin.cn/post/7069021110834036749