文章目录
- 前言
- 一、先搞懂:Redis事务到底是什么?
- 二、四大核心命令 课堂实操案例
-
- 1. MULTI + EXEC 正常提交事务
- 2. DISCARD 放弃事务,清空队列
- 3. WATCH 乐观锁,解决并发数据冲突
- 三、致命大坑:Redis事务**不支持自动回滚**
-
- 场景1:组队阶段语法错误 → 整个事务全部作废
- 场景2:组队无错误,执行时报错 → 正确命令正常生效,不会回滚
- 官方不做回滚的设计原因(面试标准答案)
- 四、Redis事务 VS MySQL事务 ACID对比
-
- Redis事务独有两个特性
- 五、Redis事务适用&不适用场景
-
- 适合使用
- 不推荐使用
- 六、期末/面试高频简答题汇总
- 结尾小结
前言
Redis事务不同于MySQL事务,接下来,请跟随我的脚步,一起来学习吧
提示:以下是本篇文章正文内容,下面案例可供参考
一、先搞懂:Redis事务到底是什么?
Redis事务和MySQL事务初衷相似:把多条Redis命令打包成一组操作,执行过程中不会被其他客户端请求插队打断。 但两者本质差别巨大:MySQL完整支持ACID四大特性,Redis只是简易事务,原子性残缺、没有隔离级别、出错不会自动回滚。
Redis事务分为两大阶段:
二、四大核心命令 课堂实操案例
1. MULTI + EXEC 正常提交事务
流程:开启事务→批量写入命令→提交统一执行
127.0.0.1> MULTI # 开启事务
OK
127.0.0.1(TX)> set username eric
QUEUED
127.0.0.1(TX)> set age 20
QUEUED
127.0.0.1(TX)> get username
QUEUED
127.0.0.1(TX)> EXEC # 提交,批量执行所有排队命令
1) OK
2) OK
3) "eric"
关键点:组队阶段无法查询数据,只有执行EXEC后,数据修改才会真正生效。
2. DISCARD 放弃事务,清空队列
写了一半发现逻辑错误,不想提交,直接丢弃所有排队指令,不会产生任何数据变更:
127.0.0.1> MULTI
OK
127.0.0.1(TX)> set k1 v1
QUEUED
127.0.0.1(TX)> DISCARD # 放弃事务
OK
127.0.0.1> get k1
(nil)
3. WATCH 乐观锁,解决并发数据冲突
这是Redis事务最核心的拓展命令,也是面试必考题。 作用:事务开启前监控一个或多个key,如果在EXEC执行前,这些key被其他客户端修改,本次事务直接作废,所有命令都不会执行。
模拟场景:账户余额100,两个客户端同时发起扣款操作 客户端1操作:
127.0.0.1> set balance 100
OK
127.0.0.1> WATCH balance # 监控余额key
OK
127.0.0.1> MULTI
OK
127.0.0.1(TX)> decrby balance 80
QUEUED
# 切到客户端执行扣款
客户端2并发操作:
127.0.0.1> decrby balance 50
(integer) 50
切回客户端1执行提交:
127.0.0.1(TX)> EXEC
(nil) # 返回nil,事务失效,防止超扣
原理和数据库乐观锁版本号思路一致,完美解决并发修改覆盖问题。
三、致命大坑:Redis事务不支持自动回滚
90%初学者都会踩这个雷,分两种报错场景区分,期末必考:
场景1:组队阶段语法错误 → 整个事务全部作废
输入命令格式非法,入队时直接报错,后续执行EXEC会直接丢弃所有指令,一条都不执行。
127.0.0.1> MULTI
OK
127.0.0.1(TX)> set k1 # 缺少value,语法错误,入队报错
(error) ERR wrong number of arguments for 'set'
127.0.0.1(TX)> set k2 v2
QUEUED
127.0.0.1(TX)> EXEC
(error) EXECABORT Transaction discarded because of previous errors.
# k1、k2均无数据
场景2:组队无错误,执行时报错 → 正确命令正常生效,不会回滚
命令语法没问题,但操作数据类型不匹配,执行失败时,其他正常执行的命令不会撤销。
127.0.0.1> MULTI
OK
127.0.0.1(TX)> set num 100 # 正常指令
QUEUED
127.0.0.1(TX)> incr numstr # numstr不存在,无法自增,执行报错
QUEUED
127.0.0.1(TX)> set name eric # 正常指令
QUEUED
127.0.0.1(TX)> EXEC
1) OK
2) (error) ERR value is not an integer or out of range
3) OK
执行完成后,num=100、name=eric真实存入Redis,报错语句直接跳过,没有任何回滚操作。
官方不做回滚的设计原因(面试标准答案)
四、Redis事务 VS MySQL事务 ACID对比
很多面试官会提问:Redis事务满足标准ACID吗?一张表讲清差异:
| 原子性(A) | 完全满足,要么全部成功,失败全部回滚 | 残缺,执行过程不插队,但单条命令出错不会回滚其他操作 |
| 一致性© | 内置约束保障,异常自动修复数据合法 | 无内置机制,一致性需要业务代码自行维护 |
| 隔离性(I) | 提供四大隔离级别,读写互不干扰 | 无隔离级别概念,事务未提交的数据全局可见 |
| 持久性(D) | 提交后数据永久落盘 | 和事务无关,由RDB/AOF持久化配置控制 |
Redis事务独有两个特性
五、Redis事务适用&不适用场景
适合使用
不推荐使用
补充:需要强原子性统一用Lua脚本,脚本执行全程不可中断,出错不会半写入数据。
六、期末/面试高频简答题汇总
Redis事务分为哪两个阶段? 答:组队阶段(MULTI入队,命令标记QUEUED)、执行阶段(EXEC批量执行),DISCARD命令可以直接丢弃未提交的事务队列。
WATCH命令的作用是什么? 答:实现Redis乐观锁,监控指定key;若事务提交前key被外部客户端修改,EXEC会返回nil,整个事务作废。
Redis事务为什么不支持回滚? 答:Redis主打高性能,回滚会增加底层复杂度;语法、类型错误属于开发bug,测试阶段可提前发现;需要完整原子操作推荐Lua脚本。
两种事务报错处理有什么区别? 答:①入队时语法错误:整个事务直接作废;②组队无错、执行时报错:正常命令正常保存,错误语句跳过,不会回滚。
Redis事务完整支持ACID吗? 答:不支持。原子性残缺、无隔离级别,一致性需要业务代码维护,持久性由持久化配置决定,和事务本身无关。
结尾小结
之前一直用MySQL事务的固有思维写Redis代码,踩了不少坑,现在彻底分清两者的区别:Redis事务只是命令批量打包工具,不是传统关系型数据库的标准事务。 日常简单批量缓存操作、简单并发扣减场景,使用MULTI+WATCH完全够用;但支付、订单这类对数据一致性要求极高的业务,要么使用Lua脚本,要么把核心事务逻辑交给MySQL处理。
网硕互联帮助中心





评论前必须登录!
注册