Redis 事务:餐厅后厨的 “批量订单处理” 流程
目录
一、事务三阶段:从 “开始接单” 到 “批量做菜”
1. 事务开始(MULTI):“这桌开始批量点餐”
2. 命令入队:“把多个菜品订单记到小本本”
3. 事务执行(EXEC):“一次性做完全部菜品”
二、WATCH:“盯着菜价,防止中途涨价”
场景:怕 “鱼香肉丝” 涨价
原理:后厨的 “被盯菜品表(watched_keys)”
触发:菜价变了,订单作废
三、衔接 Redis 核心结构:复用与高效
四、事务的特点:“要么全做,要么全不做”
五、总结:事务的 “后厨逻辑”
如果把 Redis 客户端比作餐厅的点餐员,Redis 服务器比作后厨,那么 Redis 的事务(Transaction) 就是后厨 “批量处理一桌客人的多个菜品订单” 的流程 —— 先把所有菜品订单记下来(命令入队),再一次性做完全部菜品(事务执行),期间不被其他桌的订单打断。
一、事务三阶段:从 “开始接单” 到 “批量做菜”
1. 事务开始(MULTI
):“这桌开始批量点餐”
点餐员(客户端)对后厨喊 “MULTI”,表示 “这桌要开始批量点多个菜,别中途插单”。此时,后厨(服务器)会把点餐员的状态标记为 “事务模式”(客户端flags
属性打开REDIS_MULTI
标识)。
2. 命令入队:“把多个菜品订单记到小本本”
进入事务模式后,点餐员报的每一道菜(除EXEC
/DISCARD
/WATCH
/MULTI
这 4 个 “特殊指令” 外),后厨都不立刻做,而是记到 “事务小本本(事务队列)” 里:
-
比如点餐员报:
SET 麻婆豆腐 中辣
、GET 鱼香肉丝
、SET 米饭 2碗
—— 后厨会把这些命令按顺序存入 “小本本(multiState.commands
数组)”,每个命令记录 “菜名、参数、做法(命令实现函数)”。 -
每记一个菜,后厨会回复 “
QUEUED
”(表示 “订单已排队”)。
3. 事务执行(EXEC
):“一次性做完全部菜品”
点餐员喊 “EXEC”,表示 “这桌的菜点完了,开始做!”。后厨会按顺序执行小本本里的所有订单:
-
先做 “麻婆豆腐(中辣)”,再查 “鱼香肉丝的剩余量”,最后上 “2 碗米饭”。
-
做完所有菜后,把每道菜的结果(如 “麻婆豆腐做好了”“鱼香肉丝还有”“米饭已上”)一起回复给点餐员。
二、WATCH
:“盯着菜价,防止中途涨价”
WATCH
是 Redis 的 “乐观锁”,类比 “点餐员下单前,先盯着某道菜的价格,防止做菜时涨价导致订单亏本”。
场景:怕 “鱼香肉丝” 涨价
点餐员在下单前,对后厨说 “WATCH 鱼香肉丝”—— 意思是 “我要盯着这道菜的价格,要是做菜前它涨价了(被其他桌点走 / 原料涨价),我这桌的订单就不做了”。
原理:后厨的 “被盯菜品表(watched_keys
)”
后厨(服务器)的每个 “档口(数据库)” 都有一个 “被盯菜品表(watched_keys
字典)”,记录 “哪些菜被哪些点餐员盯着”:
-
字典的键是 “菜名(数据库键,如
鱼香肉丝
)”; -
字典的值是 “盯着这道菜的点餐员链表(客户端列表)”。
触发:菜价变了,订单作废
如果在点餐员下单后、后厨做菜前,有其他桌把 “鱼香肉丝” 点走了(对应其他客户端修改了鱼香肉丝
键),后厨会给点餐员的 “订单有效性标记(REDIS_DIRTY_CAS(客户端上属性)
)” 打钩 —— 表示 “你盯的菜变了,订单不安全了”。
等点餐员喊EXEC
时,后厨发现 “订单有效性标记” 被打钩,就会回复 “订单作废(空回复)”,这桌的菜全部不做;如果标记没打钩,才会正常做菜。
三、衔接 Redis 核心结构:复用与高效
事务的实现完全复用了 Redis 的核心数据结构,体现 “结构复用” 的设计哲学:
-
客户端与事务状态:每个客户端(点餐员)的
mstate
属性(事务状态)里,存着 “订单小本本(multiState
)”——multiState
包含 “订单数组(commands
)” 和 “订单数量(count
)”,为每个客户端单独维护事务队列。 -
字典与链表:
watched_keys
用字典实现 “菜名→点餐员列表” 的快速查找(O (1) 定位被监视的菜);事务队列用数组按 FIFO 顺序保存命令,保证执行顺序。typedef struct redisDb {// ...// 正在被WATCH命令监视的键dict *watched_keys;// ... } redisDb;
-
Redis 对象系统:事务队列里的命令参数(如
SET name "Alice"
中的name
和"Alice"
)是robj
(Redis 对象),底层用 SDS 等结构存储 —— 衔接了 “Redis 对象系统” 中 “字符串对象” 的知识。
四、事务的特点:“要么全做,要么全不做”
后厨处理事务时,会一次性执行完 “订单小本本” 里的所有菜,期间不接其他桌的新订单—— 保证这桌的菜 “要么全做,要么全不做”(原子性)。
但注意:Redis 事务没有回滚(rollback)—— 如果某道菜 “做法错误”(如命令语法无效),其他菜仍会继续做。这是 Redis 为了性能和简洁性做的取舍(回滚会增加复杂度,而 Redis 认为 “命令错误应在开发阶段避免”)。
五、总结:事务的 “后厨逻辑”
Redis 事务就像餐厅后厨的 “批量订单处理”:
-
MULTI
:告诉后厨 “开始批量点餐”; -
命令入队:把多道菜记到 “订单小本本”;
-
EXEC
:告诉后厨 “开始做所有菜”; -
WATCH
:点餐员 “盯着某道菜的价格”,防止中途变动导致订单亏本。
这种设计让客户端能 “批量发命令,一次性执行”,同时用WATCH
实现 “乐观锁” 保证数据一致性,又复用 Redis 核心结构,兼顾效率与简洁。