REDIS · LUA 原子合约

库存 Lua 合约实验台

把“读库存、查 token、判断条件、写结果”压进一次不可穿插的执行。改变参数并重复请求,观察脚本到底在哪个分支停下。

READ → WRITE 执行期间不被其他命令插入

重置实验时写入库存 key,运行后锁定。

输入 0、负数、小数或文字可触发非法参数分支。

成功后保持 token 不变再次运行,可观察幂等命中。

调用映射EVALSHA
KEYS[1] = "stock:sku-1001"
KEYS[2] = "stock:processed"
ARGV[1] = "3"
ARGV[2] = "order-2026-001"

GET stock:sku-1001

12件可售

SMEMBERS stock:processed

尚无已处理 token

本次原子执行轨迹

等待运行
KEYS[1] · 库存 keystock:sku-1001
KEYS[2] · 已处理集合stock:processed
ARGV[1] · 扣减量"3"
ARGV[2] · 请求 token"order-2026-001"
  1. 1校验 ARGV扣减量必须是正整数,token 不能为空待执行
  2. 2SISMEMBER 检查 token已经处理过就直接返回,不再扣库存待执行
  3. 3GET 并判断库存可售库存必须大于或等于本次扣减量待执行
  4. 4SADD 记录 token标记请求已被脚本接纳待执行
  5. 5DECRBY 扣减库存写入扣减后的可售数量待执行
—
尚未返回 { code: null, stock: 12, token: null }

原子执行解决“被插队”,不等于事务回滚

Redis 会从脚本第一条命令执行到最后一条,期间不会穿插另一个客户端的命令。因此两个请求不会同时读到同一份库存再各自扣减。

但脚本运行时报错不会回滚。勾选错误注入后,SADD 已经成功写入的 token 会保留,后面的 DECRBY 没有执行。真正的脚本应把参数校验放在任何写操作之前,并谨慎安排写入顺序。

结构化返回码

1
扣减成功,返回剩余库存
0
库存不足,状态未改变
2
重复请求,幂等命中
-1
参数非法,拒绝执行
ERR
脚本运行时错误,已写命令不回滚