Redis 事务
Redis事务可以一次执行多个命令,本课学习事务的使用方法和注意事项。
什么是事务
事务是一组命令的集合,事务中的命令会按顺序执行,不会被其他命令打断。
MULTI → 命令1 → 命令2 → 命令3 → EXEC
基本命令
MULTI:开始事务
REDIS
MULTI
OK
EXEC:执行事务
REDIS
MULTI
OK
SET name "Alice"
QUEUED
SET age 25
QUEUED
EXEC
1) OK
2) OK
DISCARD:取消事务
REDIS
MULTI
OK
SET name "Bob"
QUEUED
DISCARD
OK
事务特性
命令队列
事务中的命令不会立即执行,而是进入队列:
REDIS
MULTI
OK
SET a 1
QUEUED
SET b 2
QUEUED
GET a
QUEUED
EXEC
1) OK
2) OK
3) "1"
原子性
事务中的命令要么全部执行,要么全部不执行:
REDIS
MULTI
OK
SET a 1
QUEUED
SET b 2
QUEUED
EXEC
1) OK
2) OK
⚠️ 注意: Redis事务不支持回滚。如果事务中某个命令执行失败,其他命令仍然会执行。
WATCH:乐观锁
WATCH用于监视键,如果键在事务执行前被修改,事务会被取消。
基本用法
REDIS
# 监视键
WATCH mykey
OK
# 开始事务
MULTI
OK
# 修改键
SET mykey "new_value"
QUEUED
# 执行事务
EXEC
(nil) # 返回nil表示事务被取消(键被修改)
实现乐观锁
示例:乐观锁
BASH
# 客户端1
WATCH balance
GET balance
MULTI
SET balance 900
EXEC
# 客户端2(在客户端1执行EXEC之前)
SET balance 800
使用场景
1. 扣减库存
示例:扣减库存
BASH
# 扣减库存(原子操作)
MULTI
DECR stock:product:123
INCR sold:product:123
EXEC
2. 转账
示例:转账
BASH
# 转账:从用户A转100到用户B
MULTI
DECRBY balance:user:a 100
INCRBY balance:user:b 100
EXEC
3. 批量操作
示例:批量操作
BASH
# 批量设置多个键
MULTI
SET user:1:name "Alice"
SET user:1:age 25
SET user:1:email "alice@example.com"
EXEC
事务 vs 脚本
Lua脚本(推荐)
Lua脚本比事务更强大,支持条件判断和循环:
REDIS
# 原子操作:如果余额足够则扣减
EVAL "
local balance = tonumber(redis.call('GET', KEYS[1]) or 0)
if balance >= tonumber(ARGV[1]) then
redis.call('DECRBY', KEYS[1], ARGV[1])
return 1
else
return 0
end
" 1 balance:user:a 100
事务 vs 脚本对比
| 特性 | 事务 | Lua脚本 |
|---|---|---|
| 原子性 | ✅ | ✅ |
| 条件判断 | ❌ | ✅ |
| 循环 | ❌ | ✅ |
| 性能 | 较好 | 更好 |
| 复杂度 | 简单 | 较复杂 |
注意事项
⚠️ 不支持回滚: Redis事务不支持回滚,如果某个命令失败,其他命令仍然会执行。
⚠️ 命令错误: 语法错误会导致事务被取消,运行时错误不会影响其他命令。
💡 推荐使用Lua脚本: 对于复杂的原子操作,推荐使用Lua脚本。
❓ 常见问题
Q Redis事务支持回滚吗?
A 不支持。Redis事务不支持回滚,如果需要回滚功能,使用Lua脚本。
Q WATCH的作用是什么?
A WATCH用于实现乐观锁,监视键是否被修改,如果被修改则取消事务。
Q 事务中的命令是原子执行的吗?
A 是的。事务中的命令会按顺序执行,不会被其他命令打断。
📖 小节
- MULTI开始事务、EXEC执行事务、DISCARD取消事务
- 事务中的命令进入队列,EXEC时按顺序执行
- WATCH用于乐观锁,监视键是否被修改
- Redis事务不支持回滚
- 复杂原子操作推荐使用Lua脚本
📝 作业
- 事务练习: 使用MULTI/EXEC执行多个命令
- 乐观锁练习: 使用WATCH实现一个简单的乐观锁
- Lua脚本练习: 使用EVAL执行一个Lua脚本
下一课
下一课我们将学习 Redis 持久化,了解RDB和AOF两种持久化方式。



