本文目录导读:

- 核心结论:先更新 DB,后删缓存(Cache-Aside 模式)
- 为什么不建议“先删缓存,后更新 DB”?
- “先更新 DB,后删缓存”的并发风险与补救
- 最终方案建议(结合 PHP 实际场景)
- 特殊情况:删除缓存失败怎么办?
- 总结(决策表)
在 PHP 开发中,先删缓存还是后删缓存”的问题,90% 的情况下应该选择“先更新数据库,后删缓存”。
这涉及经典的缓存一致性策略,以下是详细的分析和最佳实践:
核心结论:先更新 DB,后删缓存(Cache-Aside 模式)
这是业界最推荐、最稳妥的方式。
- 步骤:
- 更新数据库(Update DB)。
- 删除缓存(Delete Cache)。
- 原理:如果数据库更新成功但删缓存失败,下次读取会从数据库加载最新数据并回填缓存,缓存会自动恢复一致,这种方式容错率最高。
为什么不建议“先删缓存,后更新 DB”?
这种顺序会导致严重的并发脏数据问题,即 Cache Aside 的经典坑:
- 场景:线程 A(写)先删除了缓存,线程 B(读)此时来查缓存,发现缓存没数据,于是去数据库查询。
- 时序问题:
- 线程 A 删除缓存。
- 线程 B 查询 DB,拿到旧数据(因为线程 A 还没更新完 DB)。
- 线程 B 把旧数据写回缓存。
- 线程 A 此时才更新 DB 为新数据。
- 结果:数据库是新数据,缓存是旧数据,缓存被污染,且可能持续很久。
“先更新 DB,后删缓存”的并发风险与补救
这个方案并非绝对完美,也存在极端情况下的竞态(Race Condition):
- 场景:
- 线程 A(读)缓存 Miss,查询 DB 得到旧数据。
- 线程 B(写)更新 DB 为新数据,并删除缓存。
- 线程 A 将之前查到的旧数据写回缓存。
- 风险:缓存再次被旧数据污染。
- 评判:这种情况发生的概率极低,因为它要求“读”线程的查询耗时比“写”线程的更新+删除耗时还长,且步骤 2 必须在步骤 1 和步骤 3 之间穿插执行。
为了规避这个极小概率问题,通常采用“延迟双删”策略:
- 步骤:
- 更新数据库。
- 删除缓存。
- 休眠极短时间(如 500ms,视业务而定)。
- 再次删除缓存。
- 作用:延迟操作可以补掉步骤 3 中“线程 A”写回的旧缓存。
最终方案建议(结合 PHP 实际场景)
推荐顺序:先写 DB,再删缓存,必要时加延迟双删。
- 注意:如果在同一个 PHP 请求中,你刚刚更新完 DB,紧接着又要查询这条数据,此时不建议直接查缓存(因为缓存已被删),建议直接查 DB 或从返回结果中获取,避免空缓存穿透。
特殊情况:删除缓存失败怎么办?
如果你的代码执行了 delete 命令,但 Redis 返回失败(如网络抖动),此时缓存是脏的。
- 应对方案:
- 重试机制:将删除失败的 Key 发送到消息队列(MQ),由消费者异步重试。
- 设置过期时间:即使删缓存失败,Redis 的
EXPIRE(过期时间)是兜底方案,只要过期时间合理,最终会达到最终一致性。
决策表)
| 策略 | 同步性 | 并发安全性 | 推荐指数 |
|---|---|---|---|
| 先更新 DB,后删 Cache | 最终一致 | 高(推荐) | ⭐⭐⭐⭐⭐ |
| 先删 Cache,后更新 DB | 最终一致 | 低(脏数据概率大) | ⭐ |
| 先更新 DB,后删 Cache + 延迟双删 | 最终一致 | 极高(极致优化) | ⭐⭐⭐⭐⭐(高并发核心数据) |
给 PHP 开发者的最终建议:写业务逻辑时,不要写“先删缓存再更新数据库”的代码,请无条件使用“先更新数据库,然后再删除缓存的 Key”,如果项目对一致性要求苛刻,就在删除后加一个 usleep() 或异步任务做二次删除。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播