聊一聊面试中常问的Redis事务

大哥大姐们有没有人讲详细点的我想说明下,聊一聊面试中常问的Redis事务
最新回答
雨后初见彩虹

2026-07-12 11:50:15

Redis事务是Redis提供的一种将多个命令打包执行、确保中间不被其他命令干扰的机制,但功能简单且不支持回滚,通常不推荐在生产环境中使用,但面试中常被问到。以下从设计目的、基本指令、乐观锁机制、错误处理及不支持回滚的原因等方面展开介绍:

1. Redis事务的设计目的

Redis单个命令具有原子性(如GET、SET、MGET、MSET等),但涉及多个命令时,若需保证多个操作“要么全部成功,要么全部失败”,则需要事务机制。例如:用户A向用户B转账10元,需同时完成“A的余额-10”和“B的余额+10”两个操作,事务可确保这两个操作的原子性。

2. Redis事务的基本指令与用法

Redis提供5个事务相关指令,核心流程为开启事务→添加命令→执行/放弃:

  • MULTI:显式开启事务,返回OK,后续命令进入队列而非立即执行。
  • EXEC:执行事务队列中的所有命令,返回各命令结果列表。
  • DISCARD:清空事务队列,放弃当前事务。
  • WATCH key [key ...]:监视一个或多个键,若被监视键在EXEC前被其他客户端修改,事务将取消(返回nil)。
  • UNWATCH:取消所有键的监视。

案例演示:

# 初始化数据127.0.0.1:6379> SET zhaocai 100 # 用户A余额OK127.0.0.1:6379> SET tuoluo 100 # 用户B余额OK# 开启事务并执行转账127.0.0.1:6379> MULTIOK127.0.0.1:6379(TX)> DECRBY zhaocai 10 # A余额-10QUEUED127.0.0.1:6379(TX)> INCRBY tuoluo 10 # B余额+10QUEUED127.0.0.1:6379(TX)> EXEC1) (integer) 90 # A余额结果2) (integer) 110 # B余额结果3. 乐观锁机制:WATCH与CAS
  • 问题场景:若事务执行期间,其他客户端修改了被监视的键,可能导致数据不一致。例如:

    Client1开启事务,监视zhaocai和tuoluo。

    Client2在Client1执行EXEC前修改了tuoluo的余额。

    Client1的事务仍会执行,导致最终结果错误。

  • 解决方案:WATCH指令实现CAS(Compare-And-Swap)乐观锁:

    事务开启前监视键,若键在EXEC前被修改,事务取消。

    UNWATCH可取消监视。

案例演示:

# Client1监视键并开启事务127.0.0.1:6379> WATCH zhaocai tuoluoOK127.0.0.1:6379> MULTIOK127.0.0.1:6379(TX)> DECRBY zhaocai 10QUEUED127.0.0.1:6379(TX)> INCRBY tuoluo 10QUEUED# Client2修改tuoluo的余额(模拟并发冲突)# (在另一个终端执行)127.0.0.1:6379> SET tuoluo 200OK# Client1执行事务(因tuoluo被修改,事务取消)127.0.0.1:6379(TX)> EXEC(nil) # 返回nil表示事务失败4. 事务执行错误的处理

事务错误分为两类,处理方式不同:

  • EXEC前错误(如命令语法错误):

    命令无法进入队列,事务直接取消,所有命令均不执行。

    127.0.0.1:6379> MULTIOK127.0.0.1:6379(TX)> SET tuoluo # 缺少value参数,语法错误(error) ERR wrong number of arguments for 'set' command127.0.0.1:6379(TX)> EXEC(error) EXECABORT Transaction discarded because of previous errors.
  • EXEC后错误(如类型错误):

    错误命令不执行,其他命令仍执行,不满足原子性。

    127.0.0.1:6379> MULTIOK127.0.0.1:6379(TX)> SET tuoluo 100 # String类型QUEUED127.0.0.1:6379(TX)> LPOP tuoluo # 对String执行List命令,类型错误QUEUED127.0.0.1:6379(TX)> EXEC1) OK # SET命令成功2) (error) WRONGTYPE # LPOP命令失败
5. Redis事务不支持回滚的原因

Redis官方明确表示事务不支持回滚,核心原因如下:

  • 设计哲学:Redis认为事务错误通常由编程错误导致(如命令拼写错误、类型不匹配),此类错误不应进入生产环境。支持回滚会增加复杂性,而Redis追求简单高效。
  • 性能考量:回滚需记录操作日志,影响性能。Redis选择牺牲部分功能以换取更高吞吐量。
  • 责任划分:官方认为数据一致性应由开发者保证(如通过WATCH实现乐观锁),而非依赖数据库回滚机制。

官方原文:

Redis commands can fail only if called with a wrong syntax (and the problem is not detectable during the command queueing), or against keys holding the wrong data type: this means that in practical terms a failing command is the result of a programming errors, and a kind of error that is very likely to be detected during development, not in production.(Redis命令仅在语法错误或类型不匹配时失败,此类错误通常在开发阶段即可发现,而非生产环境问题。)

总结

Redis事务提供了一种轻量级的命令打包执行机制,但功能有限(不支持回滚、部分错误不保证原子性),通常建议通过Lua脚本或应用层逻辑实现更复杂的数据一致性需求。面试中需重点掌握:

  1. 事务的5个基本指令及其流程。
  2. WATCH与CAS乐观锁的使用场景。
  3. 事务错误处理的两种情况及差异。
  4. Redis不支持回滚的设计原因。