MySQL 与 Redis 分工:一个保存事实,一个加速访问
MySQL 与 Redis 章节,讲清业务系统里为什么常把 MySQL 和 Redis 放在一起用,以及读写流程、缓存命中、回源和一致性边界。
相关工具
先把两者的位置放准
很多人刚接触后端系统时,会把 MySQL 和 Redis 都理解成“存数据的东西”。这个说法不能算错,但太粗了。真正做系统设计时,更有用的理解是:MySQL 负责保存业务事实,Redis 负责让一部分高频访问更快。一个偏长期、可信、可恢复;一个偏高速、灵活、适合承接热点流量。
相关基础内容 里对 MySQL 的讲法,是从主键、外键、索引、Server 层、存储引擎、事务和日志展开。它关心的是一条数据怎样被唯一标识,查询怎样少读磁盘,更新怎样通过 redo log、binlog、undo log 等机制保证可靠。Redis 章节则从内存数据库讲起,强调它读写快,常用于缓存、消息队列、分布式锁和键值存储,还支持 String、Hash、List、Set、Zset 等数据结构。
所以开篇不急着背命令。先回答一个工程问题:为什么很多业务系统已经有 MySQL,还要再接 Redis?答案通常不是“Redis 更高级”,而是两者处理的压力不同。MySQL 适合做最终数据源,Redis 适合把热点数据放到内存里,让应用不必每次都打到数据库。

Redis 站在应用和 MySQL 之间承接热点访问;MySQL 保存完整、可信、可恢复的业务数据。
MySQL 保存的是业务事实
如果一条订单已经支付、一个用户已经注册、一笔余额已经扣减,系统必须能在重启、故障、迁移之后继续认得这些事实。MySQL 的价值就在这里。文中提到,MySQL 的架构大体分为 Server 层和存储引擎层:Server 层负责连接、权限、SQL 解析、优化和执行;存储引擎层负责数据的存储和提取,常用的 InnoDB 支持 B+ 树索引。
这意味着 MySQL 不只是把数据放进文件。它会先管理连接和权限,再解析 SQL,判断表和字段是否存在,交给优化器选择执行计划,最后由执行器和存储引擎完成读写。查询慢时,可以看索引是否命中;更新复杂时,要考虑事务、锁和日志。它的强项是结构化数据、关系约束、事务一致性和持久化恢复。
文中把索引比作书的目录,这个比喻很实用。没有索引时,MySQL 可能需要全表扫描,一个一个找;有合适索引时,可以沿着 B+ 树减少磁盘读取次数。对订单表、用户表、商品表这类数据来说,主键唯一标识一行,外键表达表之间的关系,索引用来提升查询和排序速度。这些能力决定了 MySQL 更适合当系统的“准账本”。
Redis 加速的是高频路径
Redis 的核心差异是内存。文中说,Redis 是开源的、基于内存的数据库,读写速度很快,常用于缓存、消息队列、分布式锁和键值存储。它也支持持久化、Lua 脚本、主从复制、哨兵、切片集群、发布订阅、过期删除和内存淘汰机制。
在系统里,Redis 最常见的角色是缓存。比如商品详情、首页推荐、用户权限、会话信息、配置项、短期计数,这些数据可能被频繁读取,但不一定每次都需要从 MySQL 重新查。把它们放到 Redis 后,应用可以先查内存里的缓存,命中就直接返回,未命中再访问 MySQL。
Redis 快,不只是因为“单线程”。文中解释得更细:Redis 把数据放在内存里,避免频繁磁盘访问;命令执行以单线程为主,减少线程切换和竞争;内部有适合不同场景的数据结构;网络 I/O 又使用多路复用,让一个线程能处理多个连接上的事件。Redis 6.0 之后还可以用多个 I/O 线程处理网络请求,但命令执行仍保持单线程模型。
读请求:先查缓存,再回源
实际应用中最常见的是 cache aside,也就是旁路缓存。应用收到查询请求后,先用约定好的 key 去 Redis 查。如果查到了,就把缓存结果返回给用户;如果没查到,再去 MySQL 查,查到后把结果写回 Redis,并给缓存设置合适的过期时间。
这个流程看起来多了一步,却能明显降低数据库压力。假设一个商品详情页每分钟被访问十万次,商品内容又不是每秒都变,如果所有请求都查 MySQL,数据库会把大量资源耗在重复读取上。放入 Redis 后,大部分请求在缓存命中时就结束了,MySQL 只需要处理缓存未命中、缓存过期、数据变更后的回源请求。
这里有一个容易忽略的点:缓存不是越久越好。过期时间太短,命中率低,数据库压力降不下来;过期时间太长,用户可能看到旧数据。比如商品价格、库存这类变化敏感的数据,缓存时间要谨慎;文章详情、字典配置、地区列表这类变化不频繁的数据,可以设置得更宽一些。

读请求先查 Redis,未命中再查 MySQL;写请求先保证 MySQL 成功,再处理缓存失效或更新。
写请求:先保证数据库,再处理缓存
写请求的原则要比读请求更严肃。新增订单、修改资料、扣减库存这类操作,首先要保证 MySQL 写入成功。因为 MySQL 才是完整业务数据的最终来源。写完 MySQL 后,再删除或更新 Redis 中对应的缓存,让后续读取重新回源,或者拿到新的缓存结果。
很多线上问题都出在顺序上:只更新 Redis,没有更新 MySQL;或者 MySQL 更新失败,缓存却先变了;又或者 MySQL 更新成功,但旧缓存没有失效,用户下一次仍读到旧数据。比较稳妥的做法通常是先写数据库,再删除缓存。删除比直接更新缓存更常见,因为缓存内容可能来自多表查询或复杂组装,删除后由下一次读请求重建,逻辑更简单。
这并不表示数据永远不会有短暂不一致。缓存系统很难承诺“任意时刻完全一致”。工程上通常追求的是:核心事实以 MySQL 为准,Redis 可以短时间落后,但要能被过期时间、删除缓存、重试、消息补偿或后台校验拉回正确状态。对金融余额、库存扣减这类强一致场景,不能只靠普通缓存流程糊过去。
不要把 Redis 当成 MySQL 的替代品
Redis 也有持久化。文中讲了 AOF、RDB 和混合持久化:AOF 会把写命令追加到日志文件;RDB 会把某个时刻的内存数据写成快照;混合持久化在 Redis 4.0 之后把两者结合起来,前半部分用 RDB 加快恢复,后半部分用 AOF 记录增量命令,降低数据丢失风险。
但有持久化,不等于它就适合替代 MySQL。Redis 的定位仍然偏高速访问和内存数据结构。AOF 的写回策略在性能和可靠性之间有取舍:Always 更可靠但更影响性能,No 更快但更依赖操作系统刷盘时机,Everysec 通常是在性能和少量数据丢失风险之间折中。RDB 快照恢复快,但快照间隔太长时,故障后可能丢失更多数据。
对多数业务系统来说,正确姿势是让 MySQL 保存最终状态,让 Redis 保存可以重建、可以过期、可以短暂失效的派生数据。缓存没了,可以从 MySQL 回源;MySQL 的事实错了,缓存再快也只是把错误传播得更快。
面试和实战里可以这样讲
如果被问“为什么用了 MySQL 还要用 Redis”,可以按三句话回答:第一,MySQL 负责持久化和事务,适合保存结构化业务数据;第二,Redis 基于内存,支持丰富数据结构和原子操作,适合缓存、计数、分布式锁、Session 等高频场景;第三,两者一起用时,读请求通常先查 Redis,未命中回源 MySQL,写请求通常先保证 MySQL 成功,再删除或更新缓存。
如果继续追问“Redis 为什么快”,再补充内存访问、单线程命令执行、I/O 多路复用和高效数据结构。文中这几条都写得很清楚:内存比磁盘快,单线程避免了多线程上下文切换和锁竞争,多路复用可以同时监听多个 Socket,String、Hash、List、Set、Zset 又让常见业务模型能用更合适的数据结构表达。
真正编写程序时,则要把抽象落到几个具体选择:哪些数据值得缓存,key 怎么设计,过期时间多长,未命中时是否允许回源,写入后删除缓存还是更新缓存,缓存异常时系统能不能降级。把这些问题想清楚,MySQL 和 Redis 就不是两个孤立名词,而是一条完整读写链路里的两个角色。
常见问题
Redis 有持久化,为什么还不能直接替代 MySQL?
Redis 可以通过 AOF、RDB、混合持久化降低数据丢失风险,但它的主要优势仍是内存访问和高频场景。MySQL 更适合结构化关系数据、事务、索引查询和最终事实保存。
读请求一定要先查 Redis 吗?
不一定。只有高频读取、计算成本高、允许短暂过期或可重建的数据才适合缓存。低频数据、强一致数据、实时变化数据未必需要先查 Redis。
写请求后应该更新缓存还是删除缓存?
很多业务会选择先写 MySQL,再删除缓存,让下一次读请求重新加载。直接更新缓存也可以,但要保证缓存内容和数据库更新逻辑完全一致,否则容易留下旧数据或脏数据。
MySQL 的查询缓存和 Redis 缓存是一回事吗?
不是。文中提到 MySQL 8.0 已不再走查询缓存阶段。Redis 是独立缓存系统,可以由应用控制 key、过期时间、数据结构和失效策略,使用方式更灵活。