Redis事务

Redis事务

引言

我们通常理解的"事务",简单来说就是一句话:要么一起成功,要么一起失败,绝不能出现"只完成一半"的情况。

这就好比一场资金转账。假设用户A要给用户B转账5块钱。在程序里,这通常包含两个动作:

  1. 扣款:从用户A的账户里扣除5块钱。
  2. 入账:给用户B的账户增加5块钱。

在现实世界里,这两个动作必须是铁板一块的。如果扣款成功了,但入账失败了(比如网络突然断了),那这5块钱就凭空消失了,这在金融系统里是绝对无法容忍的灾难。反之,如果扣款失败了,入账却成功了,那银行就亏大了。 所以,我们需要一种机制,把这两个动作打包成一个"不可分割"的整体。这就是原子性(Atomicity)。

Redis执行事务的命令

第一步:WATCH

行动开始前,我们需要确保目标数据是"安全"的。WATCH 命令就是我们的"盯梢员"。

在执行事务之前,我们先用 WATCH key [key ...] 监视那些关键的键(比如用户的余额)。这就好比在转账前,你死死盯着账户余额的数字。如果在行动结束前,这个数字被其他人改动了,那我们的行动就会立刻中止,以此来避免基于过期数据做出错误的决策。

第二步:MULTI

一旦确认环境"安全",我们就可以开始收集指令了。MULTI 命令标志着事务的正式开始。

当你输入 MULTI 后,Redis会进入"排队模式"。接下来你输入的所有命令(比如扣款、入账),都不会立即执行,而是被放入一个队列中静静等待。这一步确保了我们的操作序列是完整的,不会被中间插队。

第三步:EXEC

当所有命令都准备就绪,就是发起总攻的时刻。EXEC 命令会触发队列中所有命令的执行。

Redis会一口气、按顺序地把队列里的命令全部执行完。更重要的是,它会先回头检查一下 WATCH 盯着的那些键:如果它们没变,命令就顺利执行;如果它们变了,Redis会直接放弃整个队列的操作(返回nil),绝不允许出现"半成品"的脏数据。

补充动作:解散与重置

  • DISCARD:如果你在 MULTI 之后突然不想干了,可以用 DISCARD 来清空队列,让Redis恢复到正常状态。
  • UNWATCH:如果你不想再监视某些键了,或者事务执行完毕(EXECDISCARD 后会自动取消监视),可以用 UNWATCH 来取消监视,释放资源。

"伪"原子性

在 MySQL 等传统关系型数据库中,原子性意味着"全有或全无"(All or Nothing)。如果中间出错,系统会自动执行回滚(Rollback),把数据恢复到最初的状态。

然而,Redis 事务的哲学截然不同。它奉行"简单至上 ",不支持传统意义上的回滚机制。这主要体现在两个方面:

  1. 不回滚业务错误

    如果事务中的某条命令执行失败(比如对一个字符串类型的键执行 INCR),Redis 不会撤销之前已经执行成功的命令。例如,A扣款成功了,但给B入账时命令写错了,Redis不会把A的钱还回去。它只会记录这个错误并继续执行后续命令(如果有的话)。

  2. 靠"放弃"来保证一致性

    既然不支持回滚,那怎么保证数据不出错呢?答案就是 WATCH。

    Redis 的策略是:与其出错后费力地回滚,不如在出错前直接放弃。

    通过 WATCH 机制,Redis 能够检测到数据是否被并发修改。如果检测到冲突,它不会去尝试修正数据,而是直接放弃整个事务(返回 nil)。这就把处理问题的责任推给了客户端------客户端收到失败信号后,应该重新尝试整个操作。

为什么没有回滚?

你可能会问,为什么不实现像MySQL那样的回滚机制呢?官方的解释是:Redis追求简单和极致的性能。回滚机制需要记录undo log(回滚日志),这会带来额外的开销和复杂性。对于Redis来说,大多数命令都是简单的写操作,且数据通常作为缓存存在,即使出错,也可以通过从后端数据库重新加载来恢复。因此,Redis选择了一种更轻量级的方案。

与Lua脚本的抉择

Redis还支持通过EVAL命令执行Lua脚本。Lua脚本在Redis中也是原子执行的,并且它支持真正的条件判断和错误处理。在很多场景下,Lua脚本可以替代Redis事务,甚至比事务更强大、更简洁。

那么,何时使用事务,何时使用Lua脚本呢?

  • 使用Redis事务:当你需要执行的是一组简单的、固定的Redis命令,且业务逻辑相对简单时。
  • 使用Lua脚本:当你需要复杂的逻辑判断、循环、或者需要在服务端进行复杂的计算时。Lua脚本将逻辑封装在服务端,减少了网络往返,性能通常更好。
相关推荐
悟空聊架构3 小时前
基于KaiwuDB在游乐场“刷卡+投币”双模消费系统中的落地实践
数据库·后端·架构
IvorySQL3 小时前
PostgreSQL 技术日报 (3月4日)|硬核干货 + 内核暗流一网打尽
数据库·postgresql·开源
进击的丸子6 小时前
虹软人脸服务器版SDK(Linux/ARM Pro)多线程调用及性能优化
linux·数据库·后端
NineData1 天前
NineData智能数据管理平台新功能发布|2026年1-2月
数据库·sql·数据分析
IvorySQL1 天前
双星闪耀温哥华:IvorySQL 社区两项议题入选 PGConf.dev 2026
数据库·postgresql·开源
ServBay1 天前
垃圾堆里编码?真的不要怪 PHP 不行
后端·php
ma_king1 天前
入门 java 和 数据库
java·数据库·后端
用户962377954481 天前
CTF 伪协议
php
jiayou641 天前
KingbaseES 实战:审计追踪配置与运维实践
数据库
NineData2 天前
NineData 迁移评估功能正式上线
数据库·dba