使用数据库和缓存的时候,是如何解决数据不一致的问题的?

1.缓存更新策略

1.1. 缓存旁路模式(Cache Aside)

在应用里负责管理缓存,读取时先查缓存,如果命中了则返回缓存,如果未命中就查询数据库,然后返回缓存,返回缓存的同时把数据给写入缓存中。更新的时候则是先更新数据库,然后再删除缓存。

读: 先查缓存,缓存命中则之间返回,未命中则查数据库,数据库返回数据的同时写入缓存中。这样子下一次再查的时候就可以命中缓存了。

写: 先更新数据库,更新之后删除缓存。

优点是比较简单,对数据一致性要求不高的时候大多数场景能用,缺点就是可能会有短时间的数据不一致问题,主要是在写操作中删除缓存的时候。为什么会有数据不一致的时候呢?如果在把A改为B之后,缓存里还是A,但是在删除缓存之前,此时另一个线程已经进来了要读取缓存,那么它读取到的就是A(也就是旧的数据),它命中缓存了所以不会再访问数据库,但是此时数据库是B,明显出现了数据不一致的问题。这种情况一般是在并发情况出现。

1.2.写穿透模式(Write Through)

更新数据库的同时更新缓存,保障数据一致。

读: 直接查缓存。

写: 先更新数据库再更新缓存。

优点是数据一致性比较高,缺点是每次写操作都会更新缓存,缓存的压力可能会比较大。

1.3.写回模式(Write Back)

读: 直接查缓存。

写: 先更新缓存,然后异步更新数据库。

1.4.读写双删(属于缓存旁路模式的扩展)

在应用里负责管理缓存,读取时先查缓存,如果命中了则返回缓存,如果未命中就查询数据库,然后返回缓存,返回缓存的同时把数据给写入缓存中。更新的时候则是先更新数据库,然后再删除缓存,隔段时间再删除一次缓存,也就是一共删了两次缓存。

读: 先查缓存,缓存命中则之间返回,未命中则查数据库,数据库返回数据的同时写入缓存中。这样子下一次再查的时候就可以命中缓存了。

写: 先删除缓存,然后更新数据库,更新之后再次删除缓存。

要知道缓存旁路模式在并发情况下,可能会出现数据不一致问题,如果并发量比较高的话,出现问题的概率就会变大,所以有了读写双删这个扩展的方式。

具体实现:

1.先删除缓存(防止更新数据库后获取缓存的请求获取到旧数据)

2.然后更新数据库

3.然后删除缓存(防止此时的缓存里的数据和数据库里的不一致)

读写双删相对出现数据不一致的概率比较低,但也并不是一定的,如果在A线程删除缓存之后,更新数据库之前,此时有另一个线程B进来进行读操作,因为B的缓存未命中直接访问数据库,然后又会把数据写入缓存,此时缓存里的数据就是更新前的数据,但是A依然会进行更新数据库的操作,然后就导致数据库的数据和缓存不一致,当线程C来访问的时候,因为缓存命中,所以直接读到了旧数据。

1.5.读写双删(Double Delete)

具体实现:

1.先删除缓存(防止更新数据库后获取缓存的请求获取到旧数据)

2.然后更新数据库

3.等待一段时候后

4.然后删除缓存(防止此时的缓存里的数据和数据库里的不一致)

缓存失效策略

2.1.主动失效

在数据库更新的时候,立刻删除缓存或者更新缓存。
读: 直接查缓存。

写: 先写数据库,然后删缓存或者立马更新缓存。

2.2.被动失效

给缓存设置TTL(过期时间),过期后自动失效。
读: 直接查缓存。

写: 写入缓存时,设置TTL

优点是比较简单,缺点就是在缓存过期后、更新缓存前,可能会有短暂的数据不一致。

双写一致性策略

3.1.分布式锁

在更新数据库和缓存的时候,使用分布式锁,确保操作是原子性的(要么都成功要么都失败)。主要流程就是【获取分布式锁>>更新数据库>>更新缓存>>释放分布式锁】,优点是确保强一致性,缺点也很明显,因为加了锁所以没法支持并行操作,多线程到这里变成排队的单线程操作,会导致性能比较低。适用于对性能要求不高并且对数据一致性要求很高的场景。

3.2.消息队列

通过消息队列通知更新缓存,确保最终一致性(和强一致不一样)。主要流程就是【更新数据>>发送消息>>消费者读取消息更新缓存】,优点是异步操作,性能较好,缺点也是因为异步,所以缓存会有延迟,如果在更新缓存之前有其他请求获取缓存,可能就会出现数据不一致的情况。

其他一致性策略

4.1.读写分离

顾名思义,就是把读和写分开处理,读操作是从缓存中读数据,写操作则是更新数据库,并且更新缓存(即时或者异步都可),优点就是读性能会很好,缺点就是写操作时可能会导致数据库和缓存出现数据不一致的问题。

4.2.版本控制

给缓存添加一个版本号,每次更新缓存都增加版本号,确保版本和数据库的版本一致。优点就是能保障数据的一致性,缺点是实现起来比较复杂。

相关推荐
马尔代夫哈哈哈2 小时前
Spring IoC&DI
数据库·sql
液态不合群4 小时前
[特殊字符] MySQL 覆盖索引详解
数据库·mysql
计算机毕设VX:Fegn08954 小时前
计算机毕业设计|基于springboot + vue蛋糕店管理系统(源码+数据库+文档)
数据库·vue.js·spring boot·后端·课程设计
瀚高PG实验室4 小时前
PostgreSQL到HighgoDB数据迁移
数据库·postgresql·瀚高数据库
打码人的日常分享5 小时前
智能制造数字化工厂解决方案
数据库·安全·web安全·云计算·制造
三水不滴5 小时前
Redis 过期删除与内存淘汰机制
数据库·经验分享·redis·笔记·后端·缓存
-孤存-6 小时前
MyBatis数据库配置与SQL操作全解析
数据库·mybatis
2301_822366357 小时前
使用Scikit-learn构建你的第一个机器学习模型
jvm·数据库·python
万邦科技Lafite8 小时前
一键获取京东商品评论信息,item_reviewAPI接口指南
java·服务器·数据库·开放api·淘宝开放平台·京东开放平台
自可乐8 小时前
Milvus向量数据库/RAG基础设施学习教程
数据库·人工智能·python·milvus