Redis作为缓存和数据库的数据一致性问题

Redis作为缓存和数据库的数据一致性问题

使用Redis作为缓存了,但是会有一个问题,就是当修改了数据库中的数据,这个时候缓存中响应的数据就和数据库不一致了,这个时候应该怎么办呢?注意:本文只关注最终会导致缓存和数据库中数据不一致的情况。

数据更新操作

数据更新操作,也就是对数据库执行update执行更新操作。那么对数据进行修改的同时也需要对Redis中缓存执行一些操作来解决数据不一致的问题,那么应该对Redis中的缓存数据执行同步修改操作还是删除操作呢?

修改还是删除?

首先看更新数据库后是去更新缓存操作,考虑下面两种情景:

**情景1:**用户修改自己的用户名,修改了一次后不满意,就又修改了一次,但是最后显示的却是第一次修改的用户名,第二次修改的没有显示出来。这是为什么。

首先在这期间共发起了四次请求,线程A执行第一次修改,线程B执行查询,线程C执行第二次修改,线程D执行第二次查询。着重看两次修改的线程。这是导致缓存和数据库数据不一致的关键。

如果线程A先更新数据库后,但是出现了网络延迟,缓存的更新操作延迟了,线程C更新了数据库,立马又更新了缓存,此时线程A的缓存更新操作完成了,于是,缓存中的数据就是线程A的更新数据,而数据库中的数据是最终线程C的更新数据,这就造成了数据不一致。

**情景2:**当前是写多读少的程序,用户执行了1000次修改操作,但是最后才执行了1次查询操作。那么此时就会进行1000次数据库的修改和缓存的修改,但是缓存的前999次修改都是无效的,造成了大量的时间和空间浪费,删除操作又比修改操作快,而且无数据时删除操作是不执行的。所以删除缓存是最好的选择而不是更新。

最终我们选择更新完数据库后进行删除操作

先数据库还是先缓存

我们已经知道是更新数据库,删除缓存这两个操作。那么是先更新数据库还是先删除缓存呢?同样,从用户场景出发。

先删除缓存,再更新数据库:因为对数据库操作是很慢的,而对缓存操作是很快的,所以很容易出现下面一个情景:线程A先更新数据,线程B再读取数据,线程A删除了缓存,但是由于更新数据库的速度很慢,事务还未提交,线程B又进来了,它读取缓存但是缓存被删了就去读数据库,读取到了数据库中的数据返回给了客户端,同时将数据写到了缓存中,最后线程A更新数据库的操作终于完成了。这时,数据库中保存的确实是最终修改后的新值,但是缓存中却保存着更新前的旧值。同样造成了数据不一致问题。

**先更新数据库再删除缓存:**这种操作的话,也可能会出现数据不一致的问题。就是线程B读缓存,未读到,然后去查询了数据库,但是写入缓存的时候延迟了,这时候线程A更新了数据库,并删除了缓存。最后线程B才将数据库查到的数据写入缓存。这时候缓存就是旧值,数据库中就是新值。但是由于缓存操作肯定会快于数据库操作,所以发生概率不大。但同样也有可能,所以也可以有一些策略来解决:延迟双删操作(更新数据库->第一次删除缓存---->延迟一段时间第二次删除缓存)

设置过期时间

上面所有的操作都只能尽可能地保证数据库和缓存的数据一致,但是就像没有十全十美的人一样,软件也做不到完美,所以总会有疏漏,所以在缓存上添加一个过期时间,在一段时间后自动删除,下次再获取就需要从数据库中获取数据再写入缓存,这样也保证了一致性。这也是最后的兜底方案了。

相关推荐
松果猿21 分钟前
空间数据库学习(二)—— PostgreSQL数据库的备份转储和导入恢复
数据库
Kagol28 分钟前
macOS 和 Windows 操作系统下如何安装和启动 MySQL / Redis 数据库
redis·后端·mysql
无名之逆29 分钟前
Rust 开发提效神器:lombok-macros 宏库
服务器·开发语言·前端·数据库·后端·python·rust
s91236010129 分钟前
rust 同时处理多个异步任务
java·数据库·rust
数据智能老司机37 分钟前
CockroachDB权威指南——CockroachDB 架构
数据库·分布式·架构
hzulwy1 小时前
Redis常用的数据结构及其使用场景
数据库·redis
程序猿熊跃晖1 小时前
解决 MyBatis-Plus 中 `update.setProcInsId(null)` 不生效的问题
数据库·tomcat·mybatis
ashane13142 小时前
Redis 哨兵集群(Sentinel)与 Cluster 集群对比
redis
Three~stone3 小时前
MySQL学习集--DDL
数据库·sql·学习
Qi妙代码3 小时前
MYSQL基础
数据库·mysql·oracle