菜鸟笔记
提升您的技术认知

redis事务

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)

  • 调用任意命令(如 SETGET 等),命令不会立即执行,而是加入事务队列,返回 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)。

流程示例

  1. 监控键 balance
    127.0.0.1:6379> WATCH balance  # 监控账户余额
    OK
    
  2. 获取当前余额并开启事务
    127.0.0.1:6379> GET balance
    "100"
    127.0.0.1:6379> MULTI
    OK
    
  3. 模拟扣款操作(入队)
    127.0.0.1:6379> DECR balance  # 扣款 1 元,入队
    QUEUED
    
  4. 其他客户端修改 balance(模拟并发修改):
    127.0.0.1:6379> SET balance "90"  # 其他操作修改了余额
    OK
    
  5. 执行事务(失败)
    127.0.0.1:6379> EXEC  # 发现 balance 被修改,事务失败,返回 nil
    (nil)
    
  6. 处理失败(重试或放弃)
    127.0.0.1:6379> UNWATCH  # 取消监控,重新开始流程
    OK
    

5、事务的局限性

  1. 不支持回滚
    • 若命令在执行阶段失败(如类型错误),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 失败
      
  2. 无法解决所有并发问题
    • WATCH 仅能监控键是否被修改,无法处理复杂的业务逻辑冲突(如金额计算错误),需应用层处理。
  3. 性能限制
    • 事务本质是批量执行命令,若包含大量操作,可能阻塞 Redis 主线程,需合理控制事务规模。

5、适用场景

  1. 批量操作:简化多个命令的顺序执行(如先查询再更新)。
  2. 乐观锁场景:通过 WATCH 防止并发修改(如库存扣减、账户余额调整)。
  3. 简单事务逻辑:无需回滚的场景(如缓存更新、计数器批量操作)。