数据库与缓存11 分钟阅读更新于 2026-07-30

Redis 事务:MULTI、EXEC、WATCH 与命令队列

Redis 事务内容,讲清 MULTI 开启事务、命令入队、EXEC 顺序执行、WATCH 监视键变化,以及 Redis 事务和 MySQL 事务的边界。

相关工具

Redis 事务先别按 MySQL 事务理解

一听到事务,很多人会马上想到 MySQL:原子性、一致性、隔离性、持久性,出错回滚,隔离级别,锁,日志。Redis 也有事务,但它解决的问题更轻。它更像是把一组命令排好队,在提交时按顺序一次性执行,执行期间不被其他客户端的命令插进来。

相关基础内容 对 Redis 事务的定义是:在 Redis 中,事务是一组命令的有序执行序列,它们被一起执行,而在执行期间不会被其他客户端的命令打断。Redis 使用 MULTI 和 EXEC 命令来实现事务。MULTI 标记事务开始;MULTI 和 EXEC 之间输入的命令不会立即执行,而是放入队列;EXEC 执行队列里的所有命令,并按顺序返回结果。同时提到,可以用 WATCH 监视一个或多个键,如果事务执行期间被监视的键被其他客户端修改,事务会被取消。

这段话里最重要的不是“事务”这个名字,而是三个动作:开启事务、命令入队、提交执行。理解这三个动作,再看 WATCH 的乐观监视,Redis 事务就不难了。

Redis 事务图解,展示客户端执行 MULTI 开启事务,命令进入队列不立即执行,EXEC 后 Redis 按顺序执行并返回结果数组,以及 WATCH 监视 key 被其他客户端修改后事务取消
Redis 事务的命令队列与 WATCH 监视

MULTI 进入事务状态,后续命令先入队;EXEC 提交后 Redis 按队列顺序执行;WATCH 监视键被修改时会取消事务。

MULTI 只是进入事务状态

MULTI 的作用是告诉 Redis:接下来这个客户端发送的一组命令,要作为一个事务来处理。执行 MULTI 后,Redis 会返回 OK,表示客户端进入事务状态。此时真正的业务命令还没有开始执行。

这和很多人想象的不一样。MULTI 后面输入 SET、INCR、HSET 等命令时,Redis 通常不会立刻修改数据,而是把这些命令放进一个队列里。客户端收到的也不是命令执行结果,而是入队成功的提示。直到 EXEC 到来,队列里的命令才会按顺序执行。

所以 MULTI 更像是打开一个收纳盒。你把后续命令一个个放进去,Redis 先记下来。这个阶段的重点是排队,不是执行。理解这一点,后面很多问题都能解释清楚。

命令入队让执行顺序变得清楚

文中说,在 MULTI 和 EXEC 之间,可以输入多个 Redis 命令。这些命令不会立即执行,而是放入一个队列中等待执行。这个队列是 Redis 事务的核心。

比如你想做三步操作:给账户计数加一,写一条状态字段,再把某个临时 key 删除。如果不用事务,三个命令会分别发送,其他客户端的命令可能穿插在中间。用了 MULTI 和 EXEC 后,这三个命令先排进队列,提交时再连续执行。

这带来的好处是顺序明确。Redis 在执行事务队列时,会按队列里的顺序处理命令。客户端最后拿到的是一个结果数组,数组里的每一项对应一条命令的执行结果。读这个结果时,也要按命令顺序对应回去,不要只看最后一个返回值。

EXEC 才是真正提交

EXEC 是提交动作。文中说,EXEC 会执行所有在 MULTI 和 EXEC 之间输入的命令,这些命令作为一个事务一起执行,而且按顺序执行。如果事务执行成功,客户端会收到一个包含所有命令执行结果的数组。

这里的一起执行,不是说所有命令同时执行,而是说 Redis 会连续处理这组命令,执行期间不会被其他客户端命令打断。Redis 本身的单线程命令执行模型,让这组命令在提交阶段具备清晰的顺序边界。

这很适合需要“几条 Redis 命令按固定顺序跑完”的场景。比如一个计数和一个状态标记要配套更新,一个队列弹出和一个处理标记要连续完成。它不适合承载复杂数据库事务那种跨表一致性,也不应该被拿来替代 MySQL 的事务能力。

入队阶段出错会影响整个事务

已有内容提到,如果在 EXEC 之前发生错误,整个事务会被取消。这个说法可以帮助我们理解入队阶段的重要性。事务提交前,Redis 要先确认队列里的命令是否能被正确收进去。如果命令本身有语法问题,或者参数数量不对,事务就可能在 EXEC 前被标记为不可执行。

这类错误和执行阶段的业务错误不是一回事。比如 SET 少传了参数,这在入队阶段就能发现;而对一个字符串执行列表操作这类类型问题,可能要到真正执行时才暴露。学习 Redis 事务时,最好把“入队是否成功”和“执行是否成功”分开看。

实际开发中,客户端库通常会帮你封装事务,但你仍然要检查 EXEC 的返回。不要以为发送了 MULTI 和 EXEC 就一定全部符合预期。Redis 事务的结果是一个数组,每条命令都有自己的结果,应用要按需要判断。

WATCH 是乐观监视

WATCH 用来监视一个或多个 key。文中说,如果在事务执行期间监视的键被其他客户端修改,事务就会被取消,从而确保事务执行的原子性。更具体地说,WATCH 常用于乐观并发控制:先盯住关键数据,再读取当前值,计算新值,最后用 MULTI 和 EXEC 提交。

举个简单例子。客户端 A WATCH balance,然后读取 balance,准备扣减。还没 EXEC 前,客户端 B 修改了 balance。等 A 执行 EXEC 时,Redis 发现被 WATCH 的 key 已经变过,就取消 A 的事务。A 需要重新读取新值,再决定是否重试。

这个模型和数据库里的悲观锁不一样。WATCH 不会把 key 锁住,不会阻止别人修改。它只是记住“我提交前这个 key 有没有变过”。如果变了,就让事务失败。也正因为它不阻塞别人,WATCH 很适合冲突不太频繁的场景。

Redis 事务的原子性要说清边界

很多面试题会问 Redis 事务是否原子。这个问题容易吵起来,原因是大家对原子性的口径不一致。如果按 相关的语境,Redis 事务强调的是:事务中的命令在 EXEC 后按顺序执行,执行期间不会被其他客户端命令打断;WATCH 监视到冲突时,事务会取消。

但它和 MySQL 那种出错后完整回滚的事务不是一类东西。Redis 没有复杂的 undo log 来帮你把已经执行过的命令恢复到执行前。对 Redis 来说,更重要的是命令队列的顺序执行和提交阶段的不中断。

所以更稳的回答是:Redis 事务保证一组命令在 EXEC 后按顺序连续执行,中间不会插入其他客户端命令;WATCH 可以在提交前发现被监视 key 的并发修改并取消事务。但 Redis 事务不等同于 MySQL 的复杂事务机制,使用时要理解它的边界。

适合放进 Redis 事务的场景

Redis 事务适合一组 Redis 命令之间需要顺序边界的场景。比如同时更新几个缓存字段,递增计数后写一条状态,向列表写入消息后更新一个索引标记。这些操作都在 Redis 内部完成,命令短,执行快。

如果还要防止并发覆盖,可以配合 WATCH。比如先 WATCH 某个 key,读取当前值,根据当前值做判断,再 MULTI 入队更新命令,最后 EXEC。如果中间这个 key 被别人改了,事务取消,应用可以重试。这个流程适合低冲突的 CAS 场景。

不适合的场景也很明显:长时间业务逻辑、跨系统调用、数据库写入、外部接口请求,都不应该塞进 Redis 事务里。Redis 事务只管理 Redis 命令队列,不会替外部系统提供一致性。

和 Lua 脚本怎么区分

前一篇分布式锁里提到过 Lua 脚本,用来把比较 unique_value 和删除 lock_key 放在一起执行。那 Redis 事务和 Lua 脚本有什么区别?事务更像是命令队列,适合把多条命令按顺序提交;Lua 脚本更像是在 Redis 内部执行一段小逻辑,适合需要读值、判断、再写入的短流程。

如果只是几条命令要顺序执行,MULTI/EXEC 很直接。如果中间有判断,比如“只有 value 等于某个值才删除”,Lua 脚本会更自然,因为判断和写入能放在一个脚本里完成。

两者不是谁替代谁。Redis 事务提供队列化提交和 WATCH 乐观监视;Lua 脚本提供更强的原子逻辑封装。写业务时先看需求:是排队执行几条命令,还是需要在 Redis 内部完成条件判断。

面试可以这样回答

如果被问 Redis 事务是什么,可以先说:Redis 事务是一组命令的有序执行序列。通过 MULTI 开启事务,MULTI 和 EXEC 之间的命令不会立即执行,而是进入队列;EXEC 提交后,Redis 按顺序执行队列里的命令,并返回结果数组。

然后补 WATCH:WATCH 可以监视一个或多个 key。如果在 EXEC 之前,被监视的 key 被其他客户端修改,事务会被取消。它更像乐观锁,适合在并发不高的场景里做 CAS 控制。

最后讲边界:Redis 事务保证 EXEC 后命令按顺序连续执行,执行期间不会被其他客户端命令打断;但它不等同于 MySQL 事务,不适合承载复杂回滚、隔离级别和跨系统一致性。这个边界说清楚,回答就比较稳。

常见问题

Redis 事务用哪些命令实现?

主要用 MULTI 和 EXEC。MULTI 开启事务状态,后续命令进入队列,EXEC 提交后按顺序执行队列中的命令。

MULTI 和 EXEC 之间的命令会立即执行吗?

不会。它们会先进入事务队列,等 EXEC 提交后再按顺序执行。

WATCH 有什么作用?

WATCH 用来监视一个或多个 key。如果 EXEC 前被监视的 key 被其他客户端修改,事务会被取消,适合做乐观并发控制。

Redis 事务和 MySQL 事务一样吗?

不一样。Redis 事务重在命令入队和顺序执行,执行期间不被其他客户端命令打断;它不提供 MySQL 那种复杂回滚和隔离级别能力。

MySQL 与 Redis

继续阅读

返回专题