redis保证缓存和数据库一致性
1.先更新缓存,后更新数据库
- 如果更新成功了,但数据库更新失败,那么此时缓存中是最新值,但是数据库中是【旧值】
- 虽然此时请求可以命中缓存,拿到正确的值,但是一旦缓失,就会从数据库中读取到【旧值】,重建缓存也是这个旧值。
2.先更新数据库,后更新缓存
- 如果更新数据库成功了,但是缓存更新失败了,那么此时数据库中是最新的值,缓存中是【旧值】。
- 之后的读请求都读到的是旧数据,只有当缓存【失效】后,才能从数据库中得到正确的值。
3.先删除缓存,再更新数据库
如果有 2 个线程要并发【读写】数据,可能会发生以下场景:
- 线程A 要更新 X=2 (原值X=1)
- 线程A 先删除缓存
- 线程B 读缓存,发现不在,从数据中读取到旧值(X=1)
- 线程A 将新值写入数据库(X=2)
- 线程B 将旧值写入缓存(X=1)
最终 X 的值在缓存中是1(旧值),在数据库中是2(新值),发生不一致。
4.先更新数据库,再删除缓存
依旧是两个线程【并发读写】数据 :
- 缓存中 X 不存在(数据库中 X=1)
- 线程A 读取数据库,得到旧值(X=1)
- 线程B 更新数据库(X=2)
- 线程B 删除缓存
- 线程A 将旧值写入缓存(X=1)
最终X的值在缓存中是1(旧值),在数据库中是2(新值),也发生不一致。
这种情况理论来说是可能发生的,但实际中真有可能发生吗?
其实概率很低,这是因为它必须满足 3 个条件:
- 缓存刚已失效
- 读写请求并发
- 更新数据库 + 删除缓存的时间(步骤3~4),要比读数据库 + 写缓存的时间短(步骤2和5)
仔细想一下,条件3发生的概率是非常低的。
因为写数据库一般会先【加锁】,所以写数据库,通常是要比读数据库的时间更长的。
这么看来,【先更新数据库 + 再删除缓存】的方案,是可以保证数据一致性的。
所以,我们应该采用这种方案(【先更新数据库 + 再删除缓存】)来操作数据库和缓存。