*Redis TRANSACTION 命令

TRANSACTION 是 Redis 的事务机制,通过 MULTI、EXEC、DISCARD 和 WATCH 命令实现一组命令的原子性执行。


*语法

*开启事务

MULTI

*提交事务

EXEC

*取消事务

DISCARD

*乐观锁监控

WATCH key [key ...]

*取消监控

UNWATCH

*参数说明

参数 类型 必填 说明
key String 是(WATCH) 要监控的键名,支持多个

*返回值

  • MULTI:返回 OK,进入事务状态
  • EXEC:
    • 成功时返回事务中各命令的返回值组成的数组
    • 若 WATCH 的键被修改,返回 (nil),事务不执行
  • DISCARD:返回 OK
  • WATCH:返回 OK
  • UNWATCH:返回 OK

*时间复杂度

  • MULTI / DISCARD / WATCH / UNWATCH:O(1) - EXEC:O(N),N 为事务中命令数量

*示例

*基本事务

> MULTI
OK
> SET balance 100
QUEUED
> DECRBY balance 30
QUEUED
> EXEC
1) OK
2) (integer) 70

*事务回滚(DISCARD)

> MULTI
OK
> SET tempkey "temp"
QUEUED
> GET tempkey
QUEUED
> DISCARD
OK
> GET tempkey
(nil)

*乐观锁(WATCH + EXEC)

> WATCH balance
OK
> MULTI
OK
> DECRBY balance 50
QUEUED
> EXEC
(nil)        -- 执行期间 balance 被其他客户端修改,事务放弃

*复杂事务操作

> MULTI
OK
> HSET user:1 name "Alice" age 30
QUEUED
> ZADD leaderboard 100 "Alice"
QUEUED
> EXPIRE user:1 3600
QUEUED
> EXEC
1) (integer) 2
2) (integer) 1
3) (integer) 1

*常见错误

错误 原因 解决
EXEC without MULTI 未开启事务就执行 EXEC 先调用 MULTI
ERR WATCH inside MULTI is not allowed 在 MULTI 内部调用 WATCH WATCH 必须在 MULTI 之前执行
ERR EXEC without MULTI 未开启事务 确保 EXEC 前有对应的 MULTI

*最佳实践

  • 适用场景:需要原子性执行的多个操作,如转账扣减、库存扣减、排行榜更新
  • Redis 事务不支持回滚:即使事务中某个命令失败,其他命令仍会执行,需业务层处理补偿
  • WATCH 实现乐观锁,适合竞争不激烈的场景;高并发竞争建议使用 Lua 脚本或 Redis 单命令原子操作
  • 事务中的命令不会被其他客户端的命令插入,保证隔离性
  • 事务不支持条件判断,复杂逻辑建议使用 Lua 脚本

*FAQ

Q1: Redis 事务和关系型数据库事务有什么区别? A: Redis 事务没有回滚机制,仅保证命令打包原子执行。命令入队后即使语法错误,EXEC 时其他正确命令仍会执行。

Q2: WATCH 后如果键被修改,EXEC 会返回什么? A: 返回 (nil)(空回复),表示事务因乐观锁冲突被放弃,客户端应重试。

Q3: 事务中的命令会立即执行吗? A: 不会。MULTI 后所有命令进入队列,返回 QUEUED,直到 EXEC 时才一次性顺序执行。

Q4: 事务和 Lua 脚本怎么选? A: 简单命令组合用事务;需要条件判断、循环、复杂计算时用 Lua 脚本,脚本天然原子执行且更灵活。