Redis事务

ps:如果这篇帖子对于还在找工作和找实习的你有所帮助,可以关注我,给本贴点赞、评论、收藏并订阅专栏;同时不要吝啬您的花花

一、Redis事务核心定义

Redis事务是Redis提供的批量命令串行执行机制,本质是将多个独立命令打包存入命令队列,通过专属命令触发队列一次性执行,全程不被其他客户端命令插队,实现命令组的隔离执行。

不同于关系型数据库的强事务,Redis事务设计偏向轻量级、高性能,核心目标是保证命令执行的顺序性和隔离性,而非严格的ACID特性,这也是Redis保持高吞吐的关键设计之一。

二、Redis事务核心特性

  • 串行执行与隔离性:事务内所有命令会被序列化,按入队顺序依次执行,执行期间其他客户端的请求无法插入,彻底避免并发命令干扰,保证事务操作的独立性。
  • 弱原子性:事务要么全部入队、要么全部触发执行,但不支持命令执行失败后的回滚,这是Redis事务与传统数据库事务最核心的区别。
  • 命令延迟执行:开启事务后,后续命令不会立即落地执行,而是暂存到客户端事务队列,仅返回QUEUED状态标识,直到触发执行命令才统一处理。
  • 无持久性保障:Redis事务执行依赖内存操作,事务完成后数据是否持久化,取决于Redis的持久化策略(RDB/AOF),事务本身不强制保证数据落盘。

三、Redis事务核心命令详解

Redis事务围绕5个核心命令实现全生命周期管控,每个命令各司其职,配合完成事务开启、入队、执行、取消、监控操作。

1. MULTI:开启事务

用于标记事务块的起始,执行后客户端进入事务上下文,后续所有读写命令都会被加入事务队列,而非立即执行,命令固定返回OK

> MULTI
OK
    

2. 普通命令:入队事务

MULTI之后执行的Redis命令(如SET、GET、INCR等),不会立即生效,仅返回QUEUED表示已加入队列,所有命令按输入顺序暂存,等待最终触发。


> SET name redis
QUEUED
> INCR count
QUEUED
    

3. EXEC:执行事务

触发事务队列中所有命令的批量执行,按入队顺序依次运行,返回每个命令的执行结果数组;若事务被取消(DISCARD)或键被篡改(WATCH失效),则返回nil。


> EXEC
1) OK
2) (integer) 1
    

4. DISCARD:取消事务

清空当前事务队列的所有命令,退出事务上下文,客户端恢复普通命令执行模式,固定返回OK


> DISCARD
OK
    

5. WATCH/UNWATCH:乐观锁监控

WATCH用于监控指定键的变化,在EXEC执行前,若被监控键被其他客户端修改,当前事务会直接放弃执行(EXEC返回nil),实现高并发下的数据一致性;UNWATCH用于取消所有键的监控。


> WATCH balance
OK
> MULTI
OK
> DECRBY balance 100
QUEUED
> EXEC
(nil)  # 若balance被其他客户端修改,事务执行失败
    

四、Redis事务完整执行流程

  1. 开启事务:客户端执行MULTI,Redis标记当前连接进入事务模式。
  2. 命令入队:客户端发送业务命令,Redis校验语法合法性,合法则加入队列返回QUEUED,语法错误直接标记事务为失败状态。
  3. 触发/取消事务:客户端执行EXEC则批量执行队列命令;执行DISCARD则清空队列,终止事务。
  4. 结果返回:EXEC执行完毕后,按命令顺序返回每个命令的执行结果,事务结束,客户端恢复普通模式。

五、Redis事务异常处理机制

1. 语法错误(入队阶段)

若命令存在语法错误(如命令名写错、参数不匹配),Redis会直接标记事务为无效状态,后续EXEC执行时会直接拒绝运行整个事务,所有命令都不生效。

2. 运行时错误(执行阶段)

若命令语法合法,但执行时出现逻辑错误(如对字符串执行INCR操作),Redis不会终止事务,会继续执行队列中后续命令,仅报错当前命令,这也是Redis无回滚机制的核心体现。

重点:Redis不支持事务回滚,官方认为这种设计能提升事务执行性能,且开发阶段可规避大部分运行时错误,无需依赖数据库回滚兜底。

六、Redis事务与关系型数据库事务对比

原子性

弱原子性,仅保证命令批量执行,不回滚

强原子性,要么全成功,要么全回滚

隔离级别

仅实现串行化隔离,无其他隔离级别

支持读未提交、读已提交、可重复读、串行化

锁机制

乐观锁(WATCH),无悲观锁

支持悲观锁、乐观锁多种机制

性能

极高,轻量级队列执行,无额外开销

较低,需维护事务日志、锁、回滚段

适用场景

高并发、简单批量操作、无强一致性要求

金融交易、订单结算等强一致性场景

七、Redis事务实战避坑指南

  • 禁止在事务中使用阻塞命令:如BLPOP、SUBSCRIBE等,会导致事务队列阻塞,影响Redis整体性能。
  • WATCH需配合重试机制:高并发下WATCH失效概率高,需在应用层添加重试逻辑,保证业务最终执行。
  • 控制事务命令数量:事务队列过长会占用Redis内存,且批量执行时会阻塞其他请求,建议拆分大事务。
  • 集群模式慎用事务:Redis集群不支持跨槽位事务,仅能操作同一槽位的键,多键操作需确保哈希槽一致。
  • 区分语法错误和运行时错误:提前校验命令合法性,避免运行时错误导致部分命令生效、部分失败。

ps:如果这篇帖子对于还在找工作和找实习的你有所帮助,可以关注我,给本贴点赞、评论、收藏并订阅专栏;同时不要吝啬您的花花

Redis基础 文章被收录于专栏

本专栏带你从零掌握 Redis 核心知识,清晰讲解过期策略、内存淘汰等面试重点。用通俗语言拆解底层原理,搭配实战案例与常见问题总结,兼顾入门理解与面试备考,帮你快速建立完整 Redis 知识体系,轻松应对开发与面试

全部评论
可以加个 tag 的,不加标签不会推流
点赞 回复 分享
发布于 今天 17:00 湖北

相关推荐

03-17 09:38
已编辑
门头沟学院 C++
更新:我知道自己懂的东西也不是很全面,比如 Redis 默认的持久化策略我事先其实真的没有去了解。我也没能在在整个面试陷入奇怪的境地前,理解面试官的意图,尝试用理论知识把它拉回来并引导面试官的提问方向。但是我依旧觉得面试官也有很大问题。其实一面的体验就不是很好,但是二面更让我难受。虽然我也不是什么后端领域大神,但是这场面试真的让我惊呆了。我在简历上写着用 Docker Compose 部署了一个服务(后端程序+数据库+Redis+Nginx,一共四个实例),面试官一直不理解我的 Redis 使用方式,问我怎么持久化。我说不需要持久化,因为只是缓存数据和限流数据。面试官说那服务重启怎么办,数据不会丢失吗。我就说这些数据丢失也是无所谓的,而且我只需要重启后端程序,缓存依旧保留在 Redis 里。跟面试官说了很久都不明白,他觉得我的服务一重启缓存就全丢失了。后来他甚至觉得我不了解我的项目,觉得我分不清缓存是在后端程序的内存里还是 Redis 里,我很无语…我跟他说在 Redis 里,不持久化,慢慢地他就觉得我用 Redis 没有用,他觉得 Redis 缓存和走数据库一样得经过网络,没有提速效果,差不了多少,缓存到后端程序里才有意义。后来我们不聊这个了(那时我的体验已经很不好了),我们开始写算法题。我就写了一题,用滑动窗口判断是否是连续的重排子串。结果我不知道面试官是不是不懂 C++,他仿佛看不懂我的代码。我写了两版,第一个用两个 unordered map 存储短字符串的字符出现数和窗口里的字符出现数。我写完第一版时他去忙别的了,我觉得可以只用一个 unordered map 存窗口 diff,开始写着他就回来了。对于第一个版本,他就没有多问。对于第二个版本,这是我最心累的部分——他好像看不出我循环里的 i 是窗口左边界还是右边界,对于循环终止条件也不清晰,听不懂我说的对于长度 3 的短串在长度 4 的长串里只会循环 2 次的说法,一直问我第 3 次循环会发生什么,我真的很疑惑。他说我的代码肯定是错的,让我测试样例,结果我都通过,他很不解。我们就一起把面试至少三分之二的时间花在单步口头调试这个程序上,最后没时间了才进入下一个回合。下一个回合更奇特,他直接问我前端知识。虽然我在简历里写了一些前端,但是我面试的是后端,前端只是我项目的一部分。然后就是一些过场,问我 Vibe Coding、OpenClaw,我如实回答。最后到反问部分,我只想赶紧结束这次尴尬的面试,直接回答“没有问题”,然后互相道别。全程没有问到大家面经里说的 InnoDB 设计、Redis 数据结构等等。非常难受的经历。
查看5道真题和解析
点赞 评论 收藏
分享
评论
1
2
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务