redis事务
Redis 的事务(Transaction)提供了一种将多个命令组合执行的机制,确保多个操作按顺序执行,但不支持回滚(Rollback),主要用于简化批量操作和处理并发场景。以下是 Redis 事务的核心概念、命令、流程及特性的详细说明:
1、事务相关命令
命令 | 作用 |
---|---|
MULTI |
开启事务,标记后续命令进入队列(排队阶段),返回 OK 。 |
EXEC |
执行事务队列中的所有命令,返回各命令的结果列表;若中途监控键被修改,返回 nil 。 |
DISCARD |
放弃事务,清空队列并退出事务,返回 OK 。 |
WATCH key [key ...] |
监控一个或多个键,若事务执行前(EXEC 前)键被修改,则事务自动失败(EXEC 返回 nil )。 |
UNWATCH |
取消所有监控,用于主动放弃监控机制。 |
2、事务执行流程
2.1.开启事务
127.0.0.1:6379> MULTI
OK # 进入事务模式,后续命令入队
2.2. 命令入队(Queue Commands)
- 调用任意命令(如
SET
、GET
等),命令不会立即执行,而是加入事务队列,返回QUEUED
。 - 语法错误检查:命令入队时会检查语法,若有错误(如命令不存在),
EXEC
时会拒绝执行整个事务。127.0.0.1:6379> SET key1 "value1" # 入队成功,返回 QUEUED QUEUED 127.0.0.1:6379> INVALID_COMMAND # 语法错误,入队失败,标记事务为 discard (error) ERR unknown command `INVALID_COMMAND`
2.3. 执行事务(EXEC)或放弃事务(DISCARD)
- 正常执行:若队列中所有命令语法正确且监控键未被修改,
EXEC
按顺序执行所有命令,返回结果列表。127.0.0.1:6379> EXEC # 执行事务 1) OK # SET key1 "value1" 的结果 2) (error) ERR unknown command `INVALID_COMMAND` # 语法错误的命令导致执行失败
- 放弃事务:调用
DISCARD
会清空队列,退出事务模式。127.0.0.1:6379> DISCARD OK
3、事务的特性(与传统数据库的对比)
特性 | Redis 事务 | 传统数据库事务 |
---|---|---|
原子性(Atomicity) | 队列中的命令要么全部执行,要么全部不执行(仅在入队阶段有语法错误时); 执行阶段单命令失败不影响其他命令。 |
整个事务要么全部成功,要么回滚。 |
一致性(Consistency) | 保证事务执行前后数据状态合法(依赖应用层逻辑)。 | 事务执行前后数据满足完整性约束。 |
隔离性(Isolation) | 命令按入队顺序串行执行,无并发问题(单线程模型)。 | 支持多种隔离级别(如读未提交、可重复读)。 |
持久性(Durability) | 取决于持久化策略(RDB/AOF),与事务无关。 | 由数据库持久化机制保证(如 WAL 日志)。 |
4、乐观锁机制:WATCH 命令
作用
- 监控键的变化,确保事务执行前键未被其他客户端修改,用于解决并发场景下的竞争条件(Race Condition)。
流程示例
- 监控键
balance
:127.0.0.1:6379> WATCH balance # 监控账户余额 OK
- 获取当前余额并开启事务:
127.0.0.1:6379> GET balance "100" 127.0.0.1:6379> MULTI OK
- 模拟扣款操作(入队):
127.0.0.1:6379> DECR balance # 扣款 1 元,入队 QUEUED
- 其他客户端修改
balance
(模拟并发修改):127.0.0.1:6379> SET balance "90" # 其他操作修改了余额 OK
- 执行事务(失败):
127.0.0.1:6379> EXEC # 发现 balance 被修改,事务失败,返回 nil (nil)
- 处理失败(重试或放弃):
127.0.0.1:6379> UNWATCH # 取消监控,重新开始流程 OK
5、事务的局限性
- 不支持回滚:
- 若命令在执行阶段失败(如类型错误),Redis 会跳过该命令,继续执行后续命令,不会回滚已执行的命令。
127.0.0.1:6379> MULTI OK 127.0.0.1:6379> SET key "value" # 入队成功 QUEUED 127.0.0.1:6379> LPUSH key "element" # 类型错误(key 是字符串,非列表) QUEUED 127.0.0.1:6379> EXEC 1) OK # SET 成功 2) (error) WRONGTYPE Operation against a key holding the wrong kind of value # LPUSH 失败
- 若命令在执行阶段失败(如类型错误),Redis 会跳过该命令,继续执行后续命令,不会回滚已执行的命令。
- 无法解决所有并发问题:
WATCH
仅能监控键是否被修改,无法处理复杂的业务逻辑冲突(如金额计算错误),需应用层处理。
- 性能限制:
- 事务本质是批量执行命令,若包含大量操作,可能阻塞 Redis 主线程,需合理控制事务规模。
5、适用场景
- 批量操作:简化多个命令的顺序执行(如先查询再更新)。
- 乐观锁场景:通过
WATCH
防止并发修改(如库存扣减、账户余额调整)。 - 简单事务逻辑:无需回滚的场景(如缓存更新、计数器批量操作)。