说说 Redis 事务

news2024/12/19 18:38:34

Redis 事务简介#

Redis 只是提供了简单的事务功能。其本质是一组命令的集合,事务支持一次执行多个命令,在事务执行过程中,会顺序执行队列中的命令,其他客户端提交的命令请求不会插入到本事务执行命令序列中。命令的执行过程是顺序执行的,但不能保证原子性。无法像 MySQL 那样,有隔离级别,出了问题之后还能回滚数据等高级操作。后面会详细分析。

Redis 事务基本指令#

Redis 提供了如下几个事务相关的基础指令。

  • MULTI开启事务,Redis 会将后续命令加到队列中,而不真正执行它们,直到后续使用EXEC来原子化的顺序执行这些命令
  • EXEC执行所有事务块内的命令
  • DISCARD取消事务,放弃执行事务块内所有的命令
  • WATCH监视一个或多个 key,若事务在执行前,这些 key 被其他命令修改,则事务被终端,不会执行事务中的任何命令
  • UNWATCH取消 WATCH命令对所有 keys 的监视

一般情况下,一个简单的 Redis 事务主要分为如下几个部分:

  1. 执行命令MULTI开启一个事务。
  2. 开启事务之后,执行命令的多个命令会依次被放入一个队列,放入成功则会返回QUEUED消息。
  3. 执行命令EXEC提交事务,Redis 会依次执行队列中的命令,并依次返回所有命令的结果。(若想放弃提交事务,则执行DISCARD)。

下图简单介绍了下 Redis 事务执行的过程:

实例分析#

下面我们来通过一些实际具体例子,来体会下 Redis 中的事务。前面我们也说到 Redis 的事务不是正真的事务,是无法完全满足标准事务的ACID特性的。通过下面的例子,我们来看看,Redis 的“破产版”事务到底存在什么问题。

  • [A]正常执行提交
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> SET a 1
QUEUED
127.0.0.1:6379> SET b 2
QUEUED
127.0.0.1:6379> EXEC
1) OK
2) OK
127.0.0.1:6379> GET a
"1"
127.0.0.1:6379> GET b
"2"

开启事务后,提交的命令都会加入队列(QUEUED),执行 EXEC 后会逐步执行命令并返回结果。这个看起来是不是和我们平时使用 MySQL 的事务操作相似,类似 start transaction 和 commit。

  • [B]正常取消事务
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> SET a 1
QUEUED
127.0.0.1:6379> SET b 2
QUEUED
127.0.0.1:6379> DISCARD
OK
127.0.0.1:6379> 
127.0.0.1:6379> GET a
(nil)
127.0.0.1:6379> GET b
(nil)

开启事务后,若不想继续事务,使用 DISCARD 取消,前面提交的命令并不会真正执行,相关的 key 值不变。这个看起来也和 MySQL 的事务相似,类似 start transaction 和 rollback。

  • [C]WATCH 监视 key
-- 线程 1 中执行
127.0.0.1:6379> del a
(integer) 1
127.0.0.1:6379> get a
(nil)
127.0.0.1:6379> SET a 0
OK
127.0.0.1:6379> WATCH a
OK
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> SET a 1
QUEUED
----------------------------------------- 线程 2 中执行
----------------------------------------- 127.0.0.1:6379> SET a 2
----------------------------------------- OK
127.0.0.1:6379> EXEC
(nil)
127.0.0.1:6379> GET a
"2"

在开启事务之前 WATCH 了 a 的值,随后再开启事务。在另一个线程中设置了 a 的值(SET a 2),然后再 EXEC 执行事务,结果为 nil,
说明事务没有被执行。因为 a 的值在 WATCH 之后发生了变化,所以事务被取消了。

需要注意的是,这里和开启事务的时间点没有关系,与 MULTI 和另一个线程设置 a 的值的先后没有关系。只要是在 WATCH 之后发生了变化。无论事务是否已经开启,执行事务(EXEC)的时候都会取消。
普通情况下,在执行 EXEC 和 DISCARD 命令时,都会默认执行 UNWATCH。

  • [D]语法错误
127.0.0.1:6379> SET a 1
OK
127.0.0.1:6379> SET b 2
OK
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> SET a 11
QUEUED
127.0.0.1:6379> SETS b 22
(error) ERR unknown command 'SETS'
127.0.0.1:6379> EXEC
(error) EXECABORT Transaction discarded because of previous errors.
127.0.0.1:6379> GET a
"1"
127.0.0.1:6379> GET b
"2"

当 Redis 开启一个事务后,若添加的命令中有语法错误,会导致事务提交失败。这种情况下事务队列中的命令都不会被执行。如上面例子中 a 和 b 的值都是原有的值。
这类在 EXEC 之前产生的错误,如命令名称错误,命令参数错误等,会在 EXEC 执行之前被检测出来,所以在发生这些错误的时候,事务会被取消,事务中的所有命令都不会执行。(这种情况看起来是不是有点像回滚了)

  • [E]运行时错误
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> SET a 1
QUEUED
127.0.0.1:6379> SET b hello
QUEUED
127.0.0.1:6379> INCR b
QUEUED
127.0.0.1:6379> EXEC
1) OK
2) OK
3) (error) ERR value is not an integer or out of range
127.0.0.1:6379> GET a
"1"
127.0.0.1:6379> GET b
"hello"

当 Redis 开启一个事务后,添加的命令没有出现前面说的语法错误,但是在运行时检测到了类型错误,导致事务最提交失败(说未完全成功可能更准确点)。此时事务并不会回滚,而是跳过错误命令继续执行。
如上面的例子,未报错的命令值已经修改,a 被设置成了 1,b 被设置为了 hello,但是报错的值未被修改,即 INCR b 类型错误,并未执行,b 的值也没有被再更新。

Redis 事务与 ACID#

通过上面的例子,我们已经知道 Redis 的事务和我们通常接触的 MySQL 等关系数据库的事务还有有一定差异的。它不保证原子性。同时 Redis 事务也没有事务隔离级别的概念。下面我们来具体看下 Redis 在 ACID 四个特性中,那些是满足的,那些是不满足的。
事务执行可以分为命令入队(EXEC 执行前)和命令实际执行(EXEC 执行之后)两个阶段。下面我们在分析的时候,很多时候都会分这两种情况来分析。

  • 原子性(A)

上面的实例分析中,[A],[B],[C]三种正常的情况,我们可以很明显的看出,是保证了原子性的
但是一些异常情况下,是不满足原子性的。

  1. 如 [D] 所示的情况,客户端发送的命令有语法错误,在命令入队列时 Redis 就判断出来了。等到执行 EXEC 命令时,Redis 就会拒绝执行所有提交的命令,返回事务失败的结果。此种情况下,事务中的所有命令都不会被执行了,是保证了原子性的
  2. 如 [E] 所示的情况,事务操作入队时,命令和操作类型不匹配,此时 Redis 没有检查出错误(这类错误是运行时错误)。等到执行 EXEC 命令后,Redis 实际执行这些命令操作时,就会报错。需要注意的是,虽然 Redis 会对错误的命令报错不执行,但是其余正确的命令会依次执行完。此种情况下,是无法保证原子性的
  3. 在执行事务的 EXEC 命令时,Redis 实例发生了故障,导致事务执行失败。此时,如果开启了 AOF 日志,那么只会有部分事务操作被记录到 AOF 日志中。使用redis-check-aof工具检测 AOF 日志文件,可以把未完成的事务操作从 AOF 文件中去除。这样一来,使用 AOF 文件恢复实例后,事务操作不会被再执行,从而保证了原子性。若使用的 RDB 模式,最新的 RDB 快照是在 EXEC 执行之前生成的,使用快照恢复之后,事务中的命令也都没有执行,从而保证了原子性。若 Redis 没有开启持久化,则重启后内存中的数据全部丢失,也就谈不上原子性了。
  • 一致性(C)

一致性指的是事务执行前后,数据符合数据库的定义和要求。这点在 Redis 事务中是满足的,不论是发生语法错误还是运行时错误,错误的命令均不会被执行。

  1. EXEC 执行之前,入队报错(实例分析中的语法错误)

事务会放弃执行,故可以保证一致性。

  1. EXEC 执行之后,实际执行时报错(实例分析中的运行时错误)

错误的命令不会被执行,正确的命令被执行,一致性可以保证。

  1. EXEC 执行时,实例宕机

若 Redis 没有开启持久化,实例宕机重启后,数据都没有了,数据是一致的。
若配置了 RDB 方式,RDB 快照不会在事务执行时执行。所以,若事务执行到一半,实例发生了故障,此时上一次 RDB 快照中不会包含事务所做的修改,而下一次 RDB 快照还没有执行,实例重启后,事务修改的数据会丢失,数据是一致的。若事务已经完成,但新一次的 RDB 快照还没有生成,那事务修改的数据也会丢失,数据也是一致的。
若配置了 AOF 方式。当事务操作还没被记录到 AOF 日志时,实例就发生故障了,使用 AOF 日志恢复后数据是一致的。若事务中的只有部分操作被记录到 AOF 日志,可以使用 redis-check-aof清除事务中已经完成的操作,数据库恢复后数据也是一致的。

  • 隔离性(I)
    1. 并发操作在 EXEC 执行前,隔离性需要通过 WATCH 机制来保证
    2. 并发操作在 EXEC 命令之后,隔离性可以保证

情况 a 可以参考前面的实例分析 WATCH 命令的使用。
情况 b,由于 Redis 是单线程执行命令,EXEC 命令执行后,Redis 会保证先把事务队列中的所有命令执行完之后再执行之后的命令。

  • 持久性(D)

若 Redis 没有开启持久化,那么就是所有数据都存储在内存中,一旦重启,数据就会丢失,因此此时事务的持久性是肯定无法得到保证的。
若 Redis 开启了持久化,当实例宕机重启,还是会有可能丢失数据,因此也并能完全保证持久性。
因此,我们可以说 Redis 事务无法一定保证持久性,仅在特殊的情况下,可以保证持久性。

关于 Redis 在开启持久化之后,为啥还会丢失数据,笔者会单独整理一篇 Redis 持久化与主从相关的文章来介绍,此处简单说下。
如果配置了 RDB 模式,在一个事务执行后,下一次 RDB 快照还未执行前,Redis 实例发生了宕机,数据就会丢失、
如果配置了 AOF 模式,而 AOF 模式的三种配置选项 no,everysec,always 也都可能会产生数据丢失的情况。

总结一下,Redis 事务对 ACID 的支持情况:

  • 具备一定的原子性,但不支持回滚
  • 满足一致性
  • 满足隔离性
  • 无法保证持久性

Redis 事务为什么不支持回滚#

看一下官网的的说明:

What about rollbacks?
Redis does not support rollbacks of transactions since supporting rollbacks would have a significant impact on the simplicity and performance of Redis.


大部分需要事务回滚的情况是程序错误导致的,这种情况一般是开发环境,生产环境不应该出现这种错误。
对于逻辑错误,例如应该加 1,结果写成了加 2,这种情况无法通过回滚来解决。
Redis 追求的是简单高效,而传统事务的实现相对复杂很多,这和 Redis 的设计思想是违背的。当我们享受 Redis 的快速时,也就无法再要求它更多。

总结#

本文主要介绍了 Redis 事务的基础指令与执行流程,并分析了其对传统 ACID 特性支持的情况,相信大家对 Redis 事务已经有了一个简单的了解。
通过上面的介绍,会发现 Redis 的事务似乎有点鸡肋,确实实际中也很少会使用。至于事务的具体实现,笔者后续文章会结合源码进行分析。今天的文章就到这里,下期我们接着学。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1742.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

MPLS综合实验

目录 实验要求 划分IP地址 首先对MPLSVPN骨干网络进行配置 首先配置IP地址 启动IGP协议 激活MPLS和LDP VRF空间的创建 将接口划入到VRF空间中 R1和R5通过静态路由在CE和PE上配置 建立MP-BGP 对站点R1和R5进行配置 首先把IP给配置好 在VRF空间中发布路由信息 对站点…

2000-2020上市公司全要素生产率LP方法含原始数据和Stata代码

1、时间:2000-2020年 2、指标包括:stkcd、year、证券代码、固定资产净额、营业总收入、营业收入、营业成本、销售费用、管理费用、财务费用、支付给职工以及为职工支付的现金、员工人数、折旧摊销、行业代码、上市日期、AB股交叉码、退市日期、年末是否…

windows下用Java跑通spark官方文档的quick-start

这里写自定义目录标题前置环境官方示例三个小坑maven文件引用不明确未传递master url前置环境 见上一篇:https://blog.csdn.net/shuzip/article/details/115606522 官方示例 https://spark.apache.org/docs/3.1.1/quick-start.html /* SimpleApp.java */ import…

廊坊特色农业 国稻种芯·中国水稻节:河北复合农业促增收

廊坊特色农业 国稻种芯中国水稻节:河北复合农业促增收 新闻中国采编网 中国新闻采编网 谋定研究中国智库网 中国农民丰收节国际贸易促进会 国稻种芯中国水稻节 中国三农智库网-功能性农业农业大健康大会报道:河北廊坊安次区“稻蟹共作”新模式 特色农业…

Codeforces Round #773 (Div. 2)

A. Hard Way 题目链接:Problem - A - Codeforces 样例输入: 5 8 10 10 4 6 2 4 6 0 1 4 2 14 1 11 2 13 2 0 0 4 0 2 4 0 1 1 1 0 0样例输出: 0.0000000 0 2.0000 0.00 1题意:给定一个三角形的三个顶点,输入保证三角…

echarts画各种形状水波图

各种形状水波图 代码 用的是echarts绘制&#xff0c;echarts相关api可以参考echarts官网&#xff0c;形状修改series.shape即可修改形状&#xff0c;这里用的是SVG路径 <html><head><meta charset"utf-8"><link href"https://fonts.google…

jQuery网页开发案例:jQuery常用API--jQuery 尺寸、位置操作及 电梯导航案例和节流阀(互斥锁)

jQuery 尺寸 以上参数为空&#xff0c;则是获取相应值&#xff0c;返回的是数字型。如果参数为数字&#xff0c;则是修改相应值。参数可以不必写单位。这个width方法不包含边框 innerWidth()包含widthpadding 注意这个要大写 outerWidth()包含width padding border outerW…

(JavaSE) 数组

文章目录1. 数组的作用2. 数组的创建及初始化2.1 数组的创建2.2 数组的初始化3. 数组的使用3.1 数组中元素的访问3.2 遍历数组方法4. 数组是引用类型4.1 JVM中的内存有那些4.2 数组如何开辟空间4.3 数组 null 的意思4.4 引用不能同时指向多个对象4.5 数组作为方法返回值5. 二维…

【一键生成】3DMAX配景楼生成插件使用教程

3DMAX室外设计师常常需要创建各种场景配楼&#xff0c;为了解决大场景制作难的情况&#xff0c;3dMax配景楼生成插件是一款傻瓜式的插件或许更能快速让你从繁重的体力劳动中解脱出来&#xff01; 【安装方法】 方法一&#xff1a;拖动插件文件到3dMax窗口。 方法二&#xff1a;…

MySQL 主要线程

文章目录MySQL 主要线程1. Master thread2. io thread3. purge thread4. page Cleaner ThreadMySQL 主要线程 1. Master thread Master thread有四大循环&#xff0c;分别是loop,background loop&#xff0c;suspend loop&#xff0c;flush loop。且四大循环的作用如下: loop…

第二篇 基于自然语言处理的漏洞检测方法综述

杨伊等 来源&#xff1a;计算机研究与发展 目录 1 相关技术 1.1 自然语言处理 1.2 漏洞检测与分析 据2021年CVE漏洞趋势安全报告&#xff0c;当前漏洞类型占比最大的5类漏洞分别是代码执行、拒绝服务、溢出、跨站脚本以及信息获取。基于自然语言处理技术实现漏洞检测的研究…

STM32F103实现激光测距传感器测距WT-VL53L0 L1

目录 本博客将采用标准库和HAL库实现 所用设备选择 引脚说明 与单片机的接线表 标准库实现 HAL库实现 本博客将采用标准库和HAL库实现 所用设备选择 单片机型号&#xff1a;STM32F103C8T6 激光测距传感器型号&#xff1a;WT-VL53L0 L1 采用串口TTL电平输出&#xff0c;可…

CSDN云IDE初次测评体验

CSDN云IDE初次测评体验 文章目录CSDN云IDE初次测评体验一、前言二、云IDE产品介绍三、云IDE使用教程1、尝试编写Python爬虫代码2、尝试编写Python可视化代码3、尝试连接MySQL数据库四、最后我想说一、前言 最近一直有收到CSDN官方私信参加这个测评云IDE活动&#xff0c;刚好这…

YOLOv5剪枝 | 模型剪枝理论篇 | 1/2

文章目录 1. 前言2. 摘要精读3. 背景4. 本文提出的解决方式5. 通道层次稀疏性的优势6. 挑战7. 缩放因素和稀疏性惩罚8. 利用BN图层中的缩放因子9. 通道剪枝和微调10. 多通道方案11. 处理跨层连接和预激活结构12. 实验结果12.1 CIFAR-10数据集剪枝效果12.2 CIFAR-100数据集剪枝效…

Kafka图形管理界面Kafka-eagle安装配置详解

Kafka Eagle是一款结合了目前大数据Kafka监控工具的特点&#xff0c;重新研发的一块开源免费的Kafka集群优秀的监控工具。它可以非常方便的监控生产环境中的offset、lag变化、partition分布、owner等。 官方网址&#xff1a;EFAK 点击下载&#xff0c;将安装包下载到电脑本地&…

pytoch安装

1、安装 Anaconda 2、检查显卡&#xff0c;驱动&#xff08;检查是否较新&#xff09; winR——cmd&#xff0c;进入命令行&#xff0c;输入&#xff1a; nvidia-smi 如果版本不够&#xff0c;去官网下载Release Notes :: CUDA Toolkit Documentation (nvidia.com) 3、创建P…

【飞桨PaddleSpeech语音技术课程】— 语音识别-流式服务-模型部分

(以下内容搬运自飞桨PaddleSpeech语音技术课程&#xff0c;点击链接可直接运行源码) 流式语音识别模型 Deepspeech2 与 Conformer 1. 前言 1.1 背景知识 语音识别(Automatic Speech Recognition, ASR) 是一项从一段音频中提取出语言文字内容的任务。 (出处&#xff1a;DLHL…

开源监控软件Zabbix5部署实战

系列文章目录 文章目录系列文章目录一、zabbix介绍一、zabbix部署1、zabbix环境2、安装zabbix的安装包安装zabbix_server安装被监控方 web001一、zabbix介绍 百度百科&#xff1a;Zabbix 是一个基于WEB界面的提供分布式系统监视以及网络监视功能的企业级的开源解决方案。它是一…

2022-10-27 工作记录--Swiper/React-解决swiper处理动态数据出现样式紊乱、抖动问题

Swiper/React-解决swiper处理动态数据出现样式紊乱、抖动问题 First of all&#xff0c;检查自己在push数据前是否先清空了数组&#xff1a; 若已清空&#xff0c;请直接往下看&#x1f441;&#x1f441;哦&#xff1b;若未清空&#xff0c;请先清空数组&#xff08;可查看我的…

机器学习笔记:支持向量机SVM

1 一些概念 1.1 线性可分 在二维空间上&#xff0c;两类点被一条直线完全分开叫做线性可分。严谨的说法是&#xff1a; D0和 D1 是 n 维欧氏空间中的两个点集。如果存在 n 维向量 w 和实数 b&#xff0c;使得所有属于 D0 的点 xi 都有 wxib>0 &#xff0c;而对于所有属于 …