Redis事务为什么不支持回滚
本篇文章给大家分享《Redis事务为什么不支持回滚》,覆盖了数据库的常见基础知识,其实一个语言的全部知识点一篇文章是不可能说完的,但希望通过这些问题,让读者对自己的掌握程度有一定的认识(B 数),从而弥补自己的不足,更好的掌握它。
Redis 有事务吗
这个答案可能会令很多人感到意外,Redis
当中是存在“事务”的。这里我把 Redis
的事务带了引号,原因在后面分析。
Redis
当中的单个命令都是原子操作,但是如果我们需要把多个命令组合操作又需要保证数据的一致性时,就可以考试使用 Redis
提供的事务(或者使用前面介绍的 Lua
脚本)。
Redis
当中,通过下面 4
个命令来实现事务:
multi
:开启事务exec
:执行事务discard
:取消事务watch
:监视
Redis
的事务主要分为以下 3
步:
- 执行命令
multi
开启一个事务。 - 开启事务之后执行的命令都会被放入一个队列,如果成功之后会固定返回
QUEUED
。 - 执行命令
exec
提交事务之后,Redis
会依次执行队列里面的命令,并依次返回所有命令结果(如果想要放弃事务,可以执行discard
命令)。
接下来让我们依次执行以下命令来体会一下 Redis
当中的事务:
multi //开启事务 set name lonely_wolf //设置 name,此时 Redis 会将命令放入队列 set age 18 //设值 age,此时 Redis 会将命令放入队列 get name //获取 name,此时 Redis 会将命令放入队列 exec //提交事务,此时会依次执行队列里的命令,并依次返回结果
执行完成之后得到如下效果:
Redis 事务实现原理
Redis
中每个客户端都有记录当前客户端的事务状态 multiState
,下面就是一个客户端 client
的数据结构定义:
typedef struct client { uint64_t id;//客户端唯一 id multiState mstate; //MULTI 和 EXEC 状态(即事务状态) //...省略其他属性 } client;
multiState
数据结构定义如下:
typedef struct multiState { multiCmd *commands;//存储命令的 FIFO 队列 int count;//命令总数 //...省略了其他属性 } multiState;
multiCmd
是一个队列,用来接收并存储开启事务之后发送的命令,其数据结构定义如下:
typedef struct multiCmd { robj **argv;//用来存储参数的数组 int argc;//参数的数量 struct redisCommand *cmd;//命令指针 } multiCmd;
我们以上面事务的示例截图中事务为例,可以得到如下所示的一个简图:
Redis 事务 ACID 特性
传统的关系型数据库中,一个事务一般都具有 ACID
特性。那么现在就让我们来分析一下 Redis
是否也满足这 ACID
四大特性。
A - 原子性
在讨论事务的原子性之前,我们先来看 2
个例子。
模拟事务在执行命令前发生异常。依次执行以下命令:
multi //开启事务 set name lonely_wolf //设置 name,此时 Redis 会将命令放入队列 get //执行一个不完成的命令,此时会报错 exec //在发生异常后提交事务
最终得到了如下图所示的结果,我们可以看到,当命令入队的时候报错时,事务已经被取消了:
模拟事务在执行命令前发生异常。依次执行以下命令:
flushall //为了防止影响,先清空数据库 multi //开启事务 set name lonely_wolf //设置 name,此时 Redis 会将命令放入队列 incr name //这个命令只能用于 value 为整数的字符串对象,此时执行会报错 exec //提交事务,此时在执行第一条命令成功,执行第二条命令失败 get name //获取 name 的值
最终得到了如下图所示的结果,我们可以看到,当执行事务报错的时候,之前已经成功的命令并没有被回滚,也就是说在执行事务的时候某一个命令失败了,并不会影响其他命令的执行,即 Redis
的事务并不会回滚:
Redis 中的事务为什么不会滚
这个问题的答案在 Redis
官网中给出了明确的解释:
总结起来主要就是 3
个原因:
Redis
作者认为发生事务回滚的原因大部分都是程序错误导致,这种情况一般发生在开发和测试阶段,而生产环境很少出现。- 对于逻辑性错误,比如本来应该把一个数加
1
,但是程序逻辑写成了加2
,那么这种错误也是无法通过事务回滚来进行解决的。 Redis
追求的是简单高效,而传统事务的实现相对比较复杂,这和Redis
的设计思想相违背。
C - 一致性
一致性指的就是事务执行前后的数据符合数据库的定义和要求。这一点 Redis
中的事务是符合要求的,上面讲述原子性的时候已经提到,不论是发生语法错误还是运行时错误,错误的命令均不会被执行。
I - 隔离性
事务中的所有命令都会按顺序执行,在执行 Redis
事务的过程中,另一个客户端发出的请求不可能被服务,这保证了命令是作为单独的独立操作执行的。所以 Redis
当中的事务是符合隔离性要求的。
D - 持久性
如果 Redis
当中没有被开启持久化,那么就是纯内存运行的,一旦重启,所有数据都会丢失,此时可以认为 Redis
不具备事务的持久性;而如果 Redis
开启了持久化,那么可以认为 Redis
在特定条件下是具备持久性的。
watch 命令
上面我们讲述 Redis
中事务时,提到的的常用命令还有一个 watch
命令,这个又是做什么用的呢?我们还是先来看一个例子。
首先打开一个客户端一,依次执行以下命令:
flushall //清空数据库 multi //开启事务 get name //获取 name,此时正常返回 nil set name lonely_wolf //设置 name get name //获取 name,此时正常应该返回 lonely_wolf
得到如下效果图:
这时候我们先不执行事务,打开另一个客户端二,来执行一个命令 set name zhangsan
:
客户端二执行成功了,这时候再返回到客户端一执行 exec
命令:
可以发现,第一句话返回了 zhangsan
。也就是说,name
这个 key
值在入队之后到 exec
之前发生了变化,一旦发生这种情况,可能会引起很严重的问题,所以在关系型数据库可以通过锁来解决这种问题,那么 Redis
当中试如何解决的呢?
是的,在 Redis
当中就是通过 watch
命令来处理这种场景的。
watch 命令的作用
watch
命令可以为 Redis
事务提供 CAS
乐观锁行为,它可以在 exec
命令执行之前,监视任意 key
值的变化,也就是说当多个线程更新同一个 key
值的时候,会跟原值做比较,一旦发现它被修改过,则拒绝执行命令,并且会返回 nil
给客户端。
下面还是让我们通过一个示例来演示一下。
打开一个客户端一,依次执行如下命令:
flushall //清空数据库 watch name //监视 name multi //开启事务 set name lonely_wolf //设置 name set age 18 // 设置 age get name //获取 name get age //获取 age
执行之后得到如下效果图:
这时候再打开一个客户端二,执行 set name zhangsan
命令:
然后再回到客户端一执行 exec
命令。这时候会发现直接返回了 nil
,也就是事务中所有的命令都没有被执行(即:只要检测到一个 key
值被修改过,那么整个事务都不会被执行):
watch 原理分析
下面是一个 Redis
服务的数据结构定义:
typedef struct redisDb { dict *watched_keys; //被 watch 命令监视的 key int id; //Database ID //...省略了其他属性 } redisDb;
可以看到,redisDb
中的 watched_keys
存储了一个字典,这个字典当中的 key
存的就是被监视的 key
,然后字典的值存的就是客户端 id
。然后每个客户端还有一个标记属性 CLIENT_DIRTY_CAS
,一旦我们执行了一些如 set
,sadd
等能修改 key
值对应 value
的命令,那么客户端的 CLIENT_DIRTY_CAS
标记属性将会被修改,后面执行事务提交命令 exec
时发现客户端的标记属性被修改过(乐观锁的体现),则会拒绝执行事务。
总结
本文主要介绍了 Redis
当中的事务机制,在介绍事务实现原理的同时从传统关系型数据库的 ACID
四大特性对比分析了 Redis
当中的事务,并最终了解到了 Redis
的事务似乎并不是那么“完美”。
理论要掌握,实操不能落!以上关于《Redis事务为什么不支持回滚》的详细介绍,大家都掌握了吧!如果想要继续提升自己的能力,那么就来关注golang学习网公众号吧!

- 上一篇
- Redis使用元素删除的布隆过滤器来解决缓存穿透问题

- 下一篇
- 关于Redis数据持久化的概念介绍
-
- 温婉的树叶
- 这篇文章内容真及时,很详细,很有用,已加入收藏夹了,关注作者了!希望作者能多写数据库相关的文章。
- 2023-06-16 13:20:16
-
- 淡淡的万宝路
- 这篇技术文章真及时,作者大大加油!
- 2023-04-25 10:29:12
-
- 苗条的小鸽子
- 好细啊,mark,感谢up主的这篇文章内容,我会继续支持!
- 2023-03-09 00:52:55
-
- 无奈的钥匙
- 很棒,一直没懂这个问题,但其实工作中常常有遇到...不过今天到这,帮助很大,总算是懂了,感谢大佬分享技术文章!
- 2023-02-15 14:40:31
-
- 灵巧的故事
- 这篇技术文章真是及时雨啊,太全面了,受益颇多,收藏了,关注up主了!希望up主能多写数据库相关的文章。
- 2023-01-31 15:34:24
-
- 甜蜜的手链
- 真优秀,一直没懂这个问题,但其实工作中常常有遇到...不过今天到这,看完之后很有帮助,总算是懂了,感谢博主分享文章内容!
- 2023-01-31 12:01:33
-
- 土豪的丝袜
- 细节满满,码起来,感谢up主的这篇文章,我会继续支持!
- 2023-01-25 13:32:33
-
- 朴实的小丸子
- 很棒,一直没懂这个问题,但其实工作中常常有遇到...不过今天到这,看完之后很有帮助,总算是懂了,感谢作者大大分享技术贴!
- 2023-01-16 03:33:33
-
- 贪玩的唇膏
- 这篇技术文章真是及时雨啊,太全面了,受益颇多,收藏了,关注up主了!希望up主能多写数据库相关的文章。
- 2023-01-12 02:06:55
-
- 专注的翅膀
- 太细致了,码住,感谢楼主的这篇文章内容,我会继续支持!
- 2023-01-11 10:38:56
-
- 甜美的高山
- 这篇技术文章真及时,大佬加油!
- 2023-01-02 15:28:29
-
- 数据库 · Redis | 1小时前 |
- RedisSentinel高可用配置详解
- 468浏览 收藏
-
- 数据库 · Redis | 12小时前 |
- Redis配置加密技巧分享
- 268浏览 收藏
-
- 数据库 · Redis | 4天前 |
- Redis性能优化配置指南
- 182浏览 收藏
-
- 数据库 · Redis | 5天前 |
- RedisHyperLogLog大数据统计技巧
- 305浏览 收藏
-
- 数据库 · Redis | 6天前 |
- Redis安全配置参数设置详解
- 252浏览 收藏
-
- 数据库 · Redis | 6天前 |
- 不同环境Redis安全配置对比与调整方法
- 374浏览 收藏
-
- 数据库 · Redis | 1星期前 |
- RedisList队列优化方法分享
- 311浏览 收藏
-
- 数据库 · Redis | 1星期前 |
- Redis主从复制故障排查指南
- 178浏览 收藏
-
- 数据库 · Redis | 1星期前 |
- Redis原子操作详解与实战应用
- 469浏览 收藏
-
- 数据库 · Redis | 1星期前 |
- Redis崩溃后重启与数据恢复方法
- 153浏览 收藏
-
- 数据库 · Redis | 1星期前 |
- Redis安全配置:强密码与访问控制设置教程
- 440浏览 收藏
-
- 数据库 · Redis | 1星期前 |
- Redis单节点迁移集群的实用方法
- 376浏览 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 514次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 499次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 484次学习
-
- AI Mermaid流程图
- SEO AI Mermaid 流程图工具:基于 Mermaid 语法,AI 辅助,自然语言生成流程图,提升可视化创作效率,适用于开发者、产品经理、教育工作者。
- 638次使用
-
- 搜获客【笔记生成器】
- 搜获客笔记生成器,国内首个聚焦小红书医美垂类的AI文案工具。1500万爆款文案库,行业专属算法,助您高效创作合规、引流的医美笔记,提升运营效率,引爆小红书流量!
- 644次使用
-
- iTerms
- iTerms是一款专业的一站式法律AI工作台,提供AI合同审查、AI合同起草及AI法律问答服务。通过智能问答、深度思考与联网检索,助您高效检索法律法规与司法判例,告别传统模板,实现合同一键起草与在线编辑,大幅提升法律事务处理效率。
- 660次使用
-
- TokenPony
- TokenPony是讯盟科技旗下的AI大模型聚合API平台。通过统一接口接入DeepSeek、Kimi、Qwen等主流模型,支持1024K超长上下文,实现零配置、免部署、极速响应与高性价比的AI应用开发,助力专业用户轻松构建智能服务。
- 729次使用
-
- 迅捷AIPPT
- 迅捷AIPPT是一款高效AI智能PPT生成软件,一键智能生成精美演示文稿。内置海量专业模板、多样风格,支持自定义大纲,助您轻松制作高质量PPT,大幅节省时间。
- 624次使用
-
- golang实现mysql数据库事务的提交与回滚
- 2023-01-07 241浏览
-
- 一文搞懂MySQL持久化和回滚的原理
- 2022-12-31 101浏览
-
- Redis事务处理的使用操作方法
- 2023-01-02 258浏览
-
- Redis 事务知识点相关总结
- 2023-01-08 313浏览
-
- Redis教程(八):事务详解
- 2023-02-24 208浏览