MULTI/EXEC 是什么
MULTI 开启一个事务,之后的命令先入队,EXEC 时按顺序一次性执行,执行期间不会被其它客户端的命令插入,这一段因此是原子的。DISCARD 放弃事务。要特别记住一点:Redis 事务没有回滚,运行时错误只影响出错的那一条命令,其余命令照常生效。
基本信息
| 命令 | MULTI / EXEC / DISCARD / WATCH / UNWATCH |
|---|---|
| 原子边界 | 命令序列不被打断,但不保证全部成功 |
| 入队错误 | 命令名或参数个数错误,EXEC 整队拒绝并返回 EXECABORT |
| 运行时错误 | 单条失败,其它命令继续执行 |
| 乐观锁 | WATCH 监视键,被改动则 EXEC 返回 nil |
典型使用场景
- 需要多条命令不被穿插执行的组合操作
- 用 WATCH 实现乐观锁:库存扣减、订单状态流转
- 批量写入时减少往返次数,同时保持不被打断
- 需要在一个往返里完成读改写但不想引入 Lua 的场景
- 交互式调试时用 DISCARD 丢弃误入队的命令
用法与边界
用法与边界
MULTI
SET account:1 900
INCRBY account:2 100
EXEC # 返回数组:[OK, 100]
MULTI
INCRBY # 参数个数错误
EXEC # (error) EXECABORT:整队被拒绝
WATCH stock:sku1 # 乐观锁:被改动则 EXEC 返回 nil
GET stock:sku1
MULTI
DECR stock:sku1
EXEC # (nil) 代表需要重试命令与语义
| 命令 | 说明 | 注意 |
|---|---|---|
| MULTI | 开启事务,后续命令入队 | 入队阶段看不到彼此的执行结果 |
| EXEC | 按序执行入队命令 | 返回数组,按入队顺序对应 |
| DISCARD | 清空入队命令 | 连接立刻恢复普通模式 |
| WATCH | 监视键,变动则放弃事务 | 必须在客户端实现重试逻辑 |
| 错误类型 | 入队错误整队拒绝,运行时错误单条失败 | 两种都不是回滚 |
MULTI 里的命令无法看到彼此的结果,需要「先读后写并根据读到的值决定下一步」时,必须改用 WATCH 或 Lua 脚本。
不要把 Redis 事务当数据库事务用:部分成功是正常状态;业务要么能容忍这种不一致,要么把逻辑放进 Lua 保证整段脚本原子执行。
事务执行是阻塞式的:入队命令越多、单条越重,累积的延迟尖刺越明显。把大量大 key 操作塞进一个 EXEC 是常见的线上毛刺来源。