数据更新时应先更新数据库还是先更新 Redis?
未标记
考查重点:权威源提交与缓存失效。若数据库是权威源,常用先提交数据库再删缓存,后续未命中重载;删除失败与旧值回填仍需可靠失效、TTL和补偿,不能声称强一致
本题目录
参考答案
本答案基于相关资料,由 AI 辅助编写,供学习与面试准备参考。如有疏漏,欢迎反馈指正。
核心回答
如果MySQL是权威数据源、Redis只是可重建缓存,常用旁路缓存策略是先更新数据库并提交事务,再删除对应缓存,后续读请求未命中时重新加载。通常不建议直接双写新值,因为并发更新的到达顺序可能让旧缓存覆盖新缓存。
这套顺序仍不是跨系统原子事务:提交后删缓存前、删除失败、并发旧值回填都可能出现陈旧读取。需要可靠失效、合理TTL与补偿,并根据业务决定哪些读取必须绕过缓存。
两个时序问题
先删缓存再更新数据库时,一个并发读可能在数据库提交前读出旧值,并把它放回缓存;数据库随后变新,缓存却继续旧。先提交数据库再删缓存通常减少这种窗口,但一个更早读出旧值、被暂停的请求,也可能在删除完成后才把旧值回填。
因此,“删缓存失败后下一次读会自动读到数据库”并不成立:旧缓存还在,读请求会继续命中。应把失效任务可靠记录,例如业务更新与outbox事件一起提交,后台重试删除;也可基于已提交binlog做CDC失效,并监控延迟和失败。
怎样收紧一致性
TTL限制旧值长期驻留,但如果回源读到延迟副本或旧事务快照,仍可能再写入旧值。新鲜度敏感的回填要评估读主库和短事务。延迟双删能清理部分迟到回填,但固定延迟覆盖不了任意长暂停,不能承诺强一致。
进一步可设计覆盖相关读写路径的互斥或版本水位校验;只给写端加锁不能阻止无锁读端回填。下单、支付等最终业务判断仍以权威数据库约束为准,缓存展示价格不能直接作为不可复核的结算依据。
追问
若Redis承担写入主存、异步落库,或使用write-through等策略,顺序需要按那套持久性协议重新讨论。本题的默认结论依赖“数据库权威、缓存可重建”这个前提。
参考资料
- 国内:JavaGuide / Snailclimb:三种常用缓存读写策略:采用提交后失效、删除失败与旧值回填的时序,解释正文中不同陈旧读取窗口。
- 国内:小林 coding:数据库和缓存如何保证一致性?:交错请求的例子说明同时更新数据库与缓存时,旧操作可能覆盖新值。
- 国内:JavaGuide / Snailclimb:缓存基础常见面试题:借鉴缓存与权威存储的分离,解释正文中数据库权威、缓存可重建的前提及新增一致性维护成本。
- 国外:Microsoft:Cache-Aside pattern:依据先改数据存储再失效缓存的模式与陈旧读限制,说明正文中推荐顺序的适用范围。
- 国外:AWS:Transactional outbox pattern:借鉴事务发件箱与重复通知的说明,解释正文中数据库提交后可靠保留缓存失效任务的做法。


