先更新数据库再删除缓存
依旧是 2 个线程并发「读写」数据:
缓存中 X 不存在(数据库 X = 1)
线程 A 读取数据库,得到旧值(X = 1)
线程 B 更新数据库(X = 2)
线程 B 删除缓存
线程 A 将旧值写入缓存(X = 1)
最终 X 的值在缓存中是 1(旧值),在数据库中是 2(新值),也发生不一致。
这种情况「理论」来说是可能发生的,但实际真的有可能发生吗?
其实概率「很低」,这是因为它必须满足 3 个条件:
缓存刚好已失效
读请求 + 写请求并发
更新数据库 + 删除缓存的时间(步骤 3-4),要比读数据库 + 写缓存时间短(步骤 2 和 5)
仔细想一下,条件 3 发生的概率其实是非常低的。
因为写数据库一般会先「加锁」,所以写数据库,通常是要比读数据库的时间更长的。
如何理解这段话?
让我来解释这个并发场景:
1. 关于时序问题:
-
读数据库(线程A):通常很快,因为是单纯的SELECT操作
-
写数据库(线程B):通常较慢,因为涉及以下步骤:
- 获取写锁(行锁或表锁)
- 执行UPDATE操作
- 写入事务日志
- 提交事务
- 释放锁
**2. 为什么说发生概率低: **
假设有以下时间轴:
线程A: 读DB(0.1s) ---------------写缓存(0.1s)
线程B: 写DB(0.3s)---删缓存(0.1s)
要发生不一致,必须满足:
- 线程B的"写DB+删缓存"(0.4s)要比线程A的"读DB+写缓存"(0.2s)更快完成
- 但实际上写DB操作本身就比读DB慢
3. 具体分析:
正常情况: T1: 线程A读DB开始 (0.1s) T2: 线程B写DB开始 (0.3s) T3: 线程A读DB完成 T4: 线程B写DB完成 T5: 线程B删缓存 T6: 线程A写缓存
在这种时序下,线程A写入缓存时,一般线程B还在执行写DB操作,根本来不及删除缓存。
所以虽然理论上可能发生不一致,但由于数据库写操作的特性(加锁、事务等),这种情况的实际发生概率非常低。