在无尽的八股文中突然醒悟,有感而发。redis作为日常开发的热门组件,不管在学习,还是在公司项目中都需要用到。接下来我们来聊一聊redis很热门的一个面试题:
面试官:用过redis吗?
我:用过。
面试官:那您能说说redis如何与数据库保证数据一致性?
我心想:啥玩意?我怎么不知道。
看完下面,你将不在迷茫。
那些杂七杂八的我这里不做阐述了,写了消耗眼球,解决不了什么屁事。
解决redis与数据库的读写一致性的解决办法:
先更新数据库再删除缓存(如果你只给面试官说这个,你是不会打动他的,最多知道你背了八股文)!
那如果你有代码相关的编写能够保证到你真正的解决过这个问题,他肯定眼前一亮。
/**
*查询接口
*/
@GetMapping("getData")
public R getData(Long id){
//缓存有数据直接在缓存取数据
if(redisUtil.exists(id.toString())){
return redisUtil.get(id.toString());
}
//缓存没有数据进行数据库的查询与重新写入缓存的操作
User user = userService.getById(id);
redisUtil.set(id.toString(),user);
return R.ok().data("user",user);
}
/**
*更新接口
*/
@PostMapping("updateData")
public R updateData(@RequestBody User user){
//先更新数据库
userService.updateById(user.getId());
//删除缓存
redisUtil.remove(user.getId().toString());
return R.ok();
}
详细说一下代码的逻辑吧:
1、先更新数据库,在删除redis缓存。如果不删除缓存,下一次来读取的就是没有更新的数据。
2、读取数据时发现没有数据了,再重新查询数据库将更新好的数据放到redis中。
注意:
这样会存在一个高并发的问题:
仍然两个请求,请求A更新数据库,请求B查询数据库。
(1) 缓存刚好失效;
(2) 请求B查询数据库,得到旧值;
(3) 请求A将新值写入数据库中;
(4) 请求A删除缓存;
(5) 请求B将查到的旧值写入缓存。
![](https://i-blog.csdnimg.cn/blog_migrate/a94bec1ffc4b3d462947c8dbec575460.png)
有问题肯定就有解决的办法了:
既然删第一次时候你进来插一脚,那我也可以等你走了继续再删一次(延时异步双删)。延时的这个时间得根据你开发的项目的实际情况来定。
![](https://i-blog.csdnimg.cn/blog_migrate/85d7dfea0fc8599d1a60525761f56ea7.png)
代码也是在更新操作后稍微更改一下下就好。
/**
*查询接口
*/
@GetMapping("getData")
public R getData(Long id){
//缓存有数据直接在缓存取数据
if(redisUtil.exists(id.toString())){
return redisUtil.get(id.toString());
}
//缓存没有数据进行数据库的查询与重新写入缓存的操作
User user = userService.getById(id);
redisUtil.set(id.toString(),user);
return R.ok().data("user",user);
}
/**
*更新接口
*/
@PostMapping("updateData")
public R updateData(@RequestBody User user){
//先更新数据库
userService.updateById(user.getId());
//删除缓存
redisUtil.remove(user.getId().toString());
//延时异步双删
try {
TimeUnit.SECONDS.sleep(secondsToSleep);
} catch (InterruptedException ie) {
Thread.currentThread().interrupt();
}
redisUtil.remove(user.getId().toString());
return R.ok();
}
采用这个以后基本上能够解决redis与数据库的读写一致性了。你给面试官把这些说出来基本上面试稳了一半。希望能够帮助到和我一样在进步的小伙伴,觉得有帮助的扣扣大拇指哦。