一文带你了解缓存和数据库一致性问题

发布时间:2026/11/6 4:22:23

一文带你了解缓存和数据库一致性问题 一文带你了解缓存和数据库一致性问题在高并发系统中缓存如Redis是提升读取性能的利器但缓存与数据库之间的数据一致性问题一直是开发者必须面对的挑战。本文将深入剖析缓存与数据库不一致的根本原因并给出可落地的解决方案配合代码示例帮助你理解。—## 为什么会出现不一致缓存和数据库设计为不同存储层各自独立运行。当数据发生写操作时如果更新顺序不当或出现并发就可能出现两种情况-缓存中有旧数据但数据库已更新导致读取到脏数据。-缓存被删除但数据库尚未更新导致后续读取穿透到数据库可能读到旧数据如果更新失败。核心矛盾在于写入数据库和更新缓存这两个操作不是原子性的。网络延迟、线程切换、系统崩溃都可能破坏一致性。—## 常见更新策略分析### 1. 先更新数据库再更新缓存问题并发更新时后更新的数据库可能先更新缓存导致缓存中存了旧值。示例线程A更新数据库为值1线程B更新数据库为值2。若B先更新缓存为2A再更新缓存为1则缓存最终为1数据库为2不一致。### 2. 先删除缓存再更新数据库问题删除缓存后其他线程读取到空缓存从数据库读到旧数据并写入缓存导致脏数据。### 3. 先更新数据库再删除缓存推荐方案理论依据删除操作比更新操作更简单失败概率低。即使删除失败可以通过重试或延迟删除补偿。—## 可运行的代码示例### 示例1基本的缓存删除 数据库更新带重试pythonimport redisimport pymysqlimport time# 初始化Redis和MySQL连接示例中为伪代码redis_client redis.StrictRedis(hostlocalhost, port6379, db0)db_conn pymysql.connect(hostlocalhost, userroot, password123456, databasetest)def update_user_name(user_id, new_name): 更新用户名采用“先更新数据库再删除缓存”策略。 如果删除缓存失败通过重试机制补偿。 # 1. 更新数据库 try: with db_conn.cursor() as cursor: sql UPDATE users SET name %s WHERE id %s cursor.execute(sql, (new_name, user_id)) db_conn.commit() except Exception as e: print(f数据库更新失败: {e}) db_conn.rollback() return # 2. 删除缓存使用重试 cache_key fuser:{user_id} max_retries 3 for attempt in range(max_retries): try: redis_client.delete(cache_key) print(f缓存删除成功key: {cache_key}) break except Exception as e: print(f缓存删除失败尝试第{attempt1}次: {e}) if attempt max_retries - 1: time.sleep(0.1) # 短暂等待后重试 else: # 记录日志后续通过异步任务补偿 print(f缓存删除最终失败需人工处理 key: {cache_key})# 调用示例update_user_name(1, 张三)注释说明- 使用重试机制补偿缓存删除失败的情况。- 若重试后仍失败记录日志以便异步补偿如通过消息队列。—### 示例2使用延迟双删策略解决并发读取问题pythonimport redisimport pymysqlimport threadingimport timeredis_client redis.StrictRedis(hostlocalhost, port6379, db0)db_conn pymysql.connect(hostlocalhost, userroot, password123456, databasetest)def update_user_with_delay_delete(user_id, new_name): 延迟双删策略 1. 先删除缓存 2. 更新数据库 3. 延迟一段时间后再次删除缓存解决并发读取到旧数据的问题 cache_key fuser:{user_id} # 第一次删除缓存 try: redis_client.delete(cache_key) except Exception as e: print(f第一次缓存删除失败: {e}) # 更新数据库 try: with db_conn.cursor() as cursor: sql UPDATE users SET name %s WHERE id %s cursor.execute(sql, (new_name, user_id)) db_conn.commit() except Exception as e: print(f数据库更新失败: {e}) db_conn.rollback() return # 第二次删除缓存延迟执行确保其他线程的缓存写入已被处理 def delayed_delete(): time.sleep(0.5) # 延迟500ms可根据业务调整 try: redis_client.delete(cache_key) print(f第二次缓存删除成功key: {cache_key}) except Exception as e: print(f第二次缓存删除失败: {e}) # 启动延迟线程或使用异步任务队列 threading.Thread(targetdelayed_delete).start()# 调用示例update_user_with_delay_delete(1, 李四)注释说明- 第一次删除缓存让后续读取直接穿透到数据库。- 更新数据库保证持久化。- 第二次删除缓存消除在“第一次删除后、数据库更新前”之间其他线程写入缓存的旧数据。- 延迟时间需根据业务读写耗时估算通常设为几百毫秒。—## 深入原理为什么延迟双删有效在“先删除缓存再更新数据库”策略中问题在于 1. 线程A删除缓存。 2. 线程B读取缓存为空从数据库读旧数据并写回缓存。 3. 线程A更新数据库为新数据。 最终缓存存旧数据数据库存新数据。延迟双删通过第二次删除将步骤2中写入的旧数据再次清除让后续读取重新从数据库获取新数据。但延迟时间必须大于线程B从读取到写入缓存的总耗时否则第二次删除可能发生在旧数据写入之前导致无效。—## 其他关键措施### 1. 缓存过期时间TTL即使上述策略失败设置合理的缓存过期时间如5分钟可以保证最终一致性。过期后缓存自动清除下次读取时从数据库获取最新数据。### 2. 消息队列异步补偿将缓存删除操作封装成消息投递到MQ。即使删除失败消费者可以重试实现最终一致性。### 3. 读写分离下的注意事项如果数据库采用主从架构更新主库后从库可能存在同步延迟。此时删除缓存后其他线程可能从从库读到旧数据。解决方案- 强制读取主库牺牲部分性能。- 增加延迟删除时间覆盖主从同步延迟。—## 总结缓存和数据库一致性问题没有银弹但通过合理选择策略和补偿机制可以满足绝大多数业务场景。核心要点-优先选择“先更新数据库再删除缓存”配合重试机制。- 若并发极高使用延迟双删或异步消息队列作为补偿。- 始终设置缓存过期时间作为兜底。- 根据业务对一致性的容忍度强一致性 vs. 最终一致性选择合适方案。实际开发中建议结合业务读写比例、并发量、数据变化频率等因素权衡。对于金融等强一致性场景可能需放弃缓存或使用分布式锁对于大多数互联网业务最终一致性配合上述策略已足够。
延伸阅读

更多相关文章

2026/10/28 6:58:10

5分钟掌握FunClip:开源免费的AI智能视频剪辑终极方案

5分钟掌握FunClip:开源免费的AI智能视频剪辑终极方案 【免费下载链接】FunClip FunASR-powered video transcription, subtitle generation, and LLM-assisted clipping tool with a local Gradio UI. 项目地址: https://gitcode.com/GitHub_Trending/fu/FunClip …

2026/10/28 12:36:32

Chart.js折线图开发指南:从入门到企业级应用

1. Chart.js折线图核心价值解析Chart.js作为当前最流行的开源可视化库之一,其折线图功能在数据监控、业务报表等场景中扮演着关键角色。我曾在多个企业级数据分析项目中深度使用这个工具,发现它最突出的优势在于:用极简的配置实现专业级图表效…

2026/11/7 3:08:20

供电公司 电工证与特种工管理心德的区别

供电公司电工证报考避坑指南:工地太忙根本没时间复习考试,良心建议在这儿 工地太忙根本没时间复习考试,这几乎是所有基层电工都遇到的难题。尤其是刚毕业的应届生,一边要适应高强度的工作节奏,一边还要准备【供电公司…

2026/11/7 3:08:20

和顺特种工备案证含金量高吗?别怕考不过白交培训费

和顺特种工备案证含金量高吗?别怕考不过白交培训费 怕考不过白交培训费?和顺特种工备案证含金量到底高不高?你不是一个人在战斗。我认识的不少河南劳务班组负责人,都曾被这个问题折磨得彻夜难眠。别急,听我给你掰扯清楚。…

2026/11/7 3:08:20

余杭电工证在哪里报名 2026河南最新政策详解

余杭电工证在哪里报名 2026河南最新政策详解 你现在正站在找工作的十字路口,手上缺一个能让你顺利入职的 特种作业证 。特别是像 余杭电工证 这样的证书,很多企业明确要求持证上岗,否则连面试资格都没有。而随着 2026河南最新政策…

2026/11/7 3:08:20

宜昌在哪考高压电工证官方回应:外省证怎么转过来

宜昌在哪考高压电工证官方回应:外省证怎么转过来 之前考的证在外省能不能转过来?这是很多在外地打工的电工朋友最关心的问题。 官方回应 来了,咱们一起看看怎么操作。 外省高压电工证能转到宜昌吗…

2026/11/7 3:03:19

二七区电工证培训机构在哪考?怕考不过白交培训费看这篇就够了

二七区电工证培训机构在哪考?怕考不过白交培训费看这篇就够了 怕考不过白交培训费?二七区电工证培训机构在哪考?这是很多想考低压电工证、高压电工证的朋友最担心的问题。很多人花了几千块报名,结果考试一失败,培训费打了水漂,整个人都蒙了。别急,这篇…

2026/11/5 15:39:06

面向复杂光照与角度的宠物面部识别鲁棒性增强策略

在智慧养宠时代,基于视觉的宠物身份识别技术正逐步从实验室走向家庭应用。然而,与配合度高的人类不同,宠物是典型的“非合作生物识别对象”——它们不会主动配合摄像头调整姿态,更无法控制光照环境。实际应用中,我们常…

2026/11/6 10:49:01

SSM电子书店源码全解析:结构、原理、部署与排错实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/11/7 0:03:08

郑州报考避坑指南:电工证和钳工证怎么选?实操考试心里没底怕挂科

郑州报考避坑指南:电工证和钳工证怎么选?实操考试心里没底怕挂科 实操考试心里没底怕挂科?你不是一个人。特别是在郑州这样的城市,很多施工企业负责人和一线作业人员在报考电工证和钳工证时都面临着同样的困惑。到底该考哪个证?哪个更适合自己?哪个证书…

2026/11/7 0:03:08

广西电工证办理流程全解析:外省证怎么转?在哪考最靠谱?

广西电工证办理流程全解析:外省证怎么转?在哪考最靠谱? 之前考的证在外省能不能转过来?这个问题我遇到太多了,今天就拿广西电工证办理流程来具体说说,别再走弯路了。广西电工证的报考、复审、继续教育这些环节,如果你不了解,真的会吃大亏,尤其对于从…

2026/11/7 0:03:08

电气电工证都有哪些保姆级教程

电气电工证都有哪些保姆级教程 你是不是正愁不知道去哪报名,怕被中介坑?别急,这篇保姆级教程专为河南初次报考人员准备,帮你搞清楚 电气电工证都有哪些 ,以及如何避开那些坑。 电气电工证都有哪些?别被五花八门的证书搞懵了…

2026/11/5 15:39:06

面向复杂光照与角度的宠物面部识别鲁棒性增强策略

在智慧养宠时代,基于视觉的宠物身份识别技术正逐步从实验室走向家庭应用。然而,与配合度高的人类不同,宠物是典型的“非合作生物识别对象”——它们不会主动配合摄像头调整姿态,更无法控制光照环境。实际应用中,我们常…

2026/11/6 10:49:01

SSM电子书店源码全解析:结构、原理、部署与排错实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑