


专栏:Redis 修行录
个人主页:手握风云
目录
[一、Redis 事务](#一、Redis 事务)
[1.1. 基础概念](#1.1. 基础概念)
[1.2. 与 MySQL 事务核心区别](#1.2. 与 MySQL 事务核心区别)
[1.3. 底层原理](#1.3. 底层原理)
[1.4. 核心命令](#1.4. 核心命令)
[1. MULTI](#1. MULTI)
[2. EXEC](#2. EXEC)
[3. DISCARD](#3. DISCARD)
[4. WATCH](#4. WATCH)
[5. UNWATCH](#5. UNWATCH)
一、Redis 事务
1.1. 基础概念
Redis 事务与 MySQL 事务核心思路相似,都是把多条操作命令绑定为一组,实现批量统一执行。但 Redis 事务是弱化版事务,不完整满足数据库标准 ACID 四大特性,和 MySQL 事务存在巨大差异。
1.2. 与 MySQL 事务核心区别
- 原子性(弱化)
MySQL 的原子性是指一组操作要么全部成功,一旦失败则全部回滚,恢复初始数据。Redis 的原子性仅保证命令连续批量执行不被插队,没有回滚能力:如果事务队列里某条命令语法报错,整个事务全部不执行;如果执行 EXEC 时某条命令运行报错,其余合法命令仍会正常执行,失败指令不会撤销,数据也不会恢复初始状态。
- 一致性(不保证)
MySQL 的一致性保证事务执行前、执行后数据均合法有效,不会出现非法中间状态,依靠约束与回滚机制实现。Redis 无法保障一致性,它不存在数据约束,也没有回滚机制,事务执行过程中有可能产生非法数据状态。
- 隔离性(完全不需要)
MySQL 存在多事务并发,设计多种隔离级别解决并发冲突。Redis 单线程串行处理所有客户端请求,同一时刻只会执行一组事务队列命令,事务内操作会一次性连续跑完,不会被其他客户端命令 "加塞",不存在事务并发场景,因此不需要隔离性、没有隔离级别。
- 持久性(和事务无关)
MySQL 事务提交后数据永久落盘,具备持久性。Redis 数据默认存储在内存,持久化依靠 RDB/AOF 独立持久化方案控制,事务本身不具备持久化能力,两者互不绑定。
1.3. 底层原理
Redis 事务以服务器维护的专属事务队列作为核心载体。当通过 MULTI 命令开启事务后便进入入队阶段,客户端提交的所有操作命令不会立刻执行,而是仅存入事务队列,服务器返回 QUEUED 标识就代表命令入队成功。后续分为执行和放弃两种分支:发送 EXEC 命令时,服务器会一次性批量执行队列内全部缓存命令,事务正式生效;发送 DISCARD 命令时,则会直接清空事务队列,队列中所有命令全部作废,不会被执行。
1.4. 核心命令
1. MULTI
bash
# 开启事务,初始化事务队列
MULTI
MULTI 是事务的开启命令,也是事务唯一的起始标识,执行后会返回 OK,完成事务队列初始化。执行该命令后客户端输入的所有读写指令不会立即执行,只会存入事务队列,返回 QUEUED 即代表命令成功入队;只有先执行 MULTI,客户端才能生成缓存命令的事务队列,一般用于批量数据操作前初始化事务环境。

2. EXEC
bash
# 提交事务,批量执行队列内所有缓存命令
EXEC
EXEC 是事务提交命令,也是唯一能批量执行队列缓存指令的入口。它分两种执行逻辑,未搭配 WATCH 监控键时,会串行完整执行队列内全部命令,逐条返回每条指令的执行结果;若提前用 WATCH 监控了指定键,提交时会对比键的版本号,一旦服务器上键的版本号发生变更,EXEC 直接返回 nil,队列中所有操作全部不执行。执行 EXEC 阶段 Redis 单线程会优先处理当前事务,外部客户端请求需排队等待,适用于事务全部操作编写完成后统一提交生效。

3. DISCARD
bash
# 放弃未提交事务,清空事务队列
DISCARD
DISCARD 是放弃未提交事务的命令,也是 Redis 在 EXEC 执行前撤销事务的唯一方式。执行后会直接清空事务队列里所有缓存指令,直接终止本次事务并返回 OK,不会对内存数据产生任何修改。由于 Redis 事务没有执行失败后的回滚机制,当编写事务中途决定放弃本次批量操作时,就可以使用 DISCARD 清空队列。

4. WATCH
bash
# 乐观锁,监控一组指定 key,用于并发数据校验
WATCH key [key ...]
WATCH 属于乐观锁监控命令,必须在 MULTI 开启事务前执行,核心作用是监控一组指定键,完成并发数据校验。服务器会为每个键维护独立版本号,键每被修改一次版本号就自动自增;执行 WATCH 时会记录目标键当时的版本信息,后续调用 EXEC 提交事务时,会对比服务器当前键版本与事务记录版本,两者不一致就代表键被其他客户端篡改,整个事务直接失效,所有命令不执行,返回 nil。。该命令仅对当前客户端生效,不存在阻塞行为,多用于高并发场景,防止事务执行期间目标键被其他客户端修改造成数据不一致。


我们现在其中一个 Redis 客户端中执行事务 set k1 222,再在另一个 Redis 客户端中不加事务执行 set k1 333,再去执行 exec,就会发现最终值是"222"。


5. UNWATCH
bash
# 取消当前客户端所有 WATCH 监控的 key
UNWATCH
UNWATCH 是取消键监控的命令,作为 WATCH 的逆向操作,手动执行后会清除当前客户端所有通过 WATCH 绑定的键版本监控记录,后续执行 EXEC 时不再做版本校验。