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才将数据库查到的数据写入缓存。这时候缓存就是旧值,数据库中就是新值。但是由于缓存操作肯定会快于数据库操作,所以发生概率不大。但同样也有可能,所以也可以有一些策略来解决:延迟双删操作(更新数据库->第一次删除缓存---->延迟一段时间第二次删除缓存)

设置过期时间

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

相关推荐
麦聪聊数据1 天前
Web 原生架构如何重塑企业级数据库协作流?
数据库·sql·低代码·架构
未来之窗软件服务1 天前
数据库优化提速(四)新加坡房产系统开发数据库表结构—仙盟创梦IDE
数据库·数据库优化·计算机软考
时艰.1 天前
Java 并发编程 — 并发容器 + CPU 缓存 + Disruptor
java·开发语言·缓存
Goat恶霸詹姆斯1 天前
mysql常用语句
数据库·mysql·oracle
大模型玩家七七1 天前
梯度累积真的省显存吗?它换走的是什么成本
java·javascript·数据库·人工智能·深度学习
曾经的三心草1 天前
redis-9-哨兵
数据库·redis·bootstrap
明哥说编程1 天前
Dataverse自定义表查询优化:D365集成大数据量提速实战【索引配置】
数据库·查询优化·dataverse·dataverse自定义表·索引配置·d365集成·大数据量提速
张小凡vip1 天前
Kubernetes--k8s中部署redis数据库服务
redis·kubernetes
xiaowu0801 天前
C# 拆解 “显式接口实现 + 子类强类型扩展” 的设计思想
数据库·oracle
讯方洋哥1 天前
HarmonyOS App开发——关系型数据库应用App开发
数据库·harmonyos