Redis的事务机制能保证ACID属性吗?

目录

事务 ACID 属性

用户如何开启Redis的事务?

使用redis-cli客户端来展示

​Go语言编码使用事务

Redis 的事务机制能保证哪些属性?

1. 原子性

语法错误

运行错误

执行EXEC时,Redis发生故障

Redis对事务原子性属性的保证情况

 2. 一致性

命令入队就错误

命令在实际执行时才报错

EXEC命令执行时,Redis发生故障

3. 隔离性 

4. 持久性

总结


为什么要把这批操作 称为 事务呢?是因为一批操作在执行过程中想获得一些保证。而事务就提供了这些保证。

事务在执行的时候,会提供专门的属性保护,包括原子性、一致性、隔离性和持久性。

事务 ACID 属性

原子性(Atomicity)

事务的整个过程如原子操作一样,最终要么全部成功,或者全部失败,这个原子性是从最终结果来看的,从最终结果来看这个过程是不可分割的。业务应用使用事务时,原子性也是最被看重的一个属性。

一致性(Consistency)
一个事务必须使数据库从一个一致性状态变换到另一个一致性状态,是指数据库中的数据在事务执行前后是一致的。

比如说转账, 用户A余额200元,用户B余额100元,A给B转账100元,事务结束后,用于A余额是100元,用户B余额是200元,这个就是一致性。如果A上的钱减少了,而B上的钱却没有增加,那么我们认为此时数据处于不一致的状态。

隔离性(Isolation)
一个事务的执行不能被其他事务干扰。它要求数据库在执行一个事务时,其它操作无法存取到正在执行事务访问的数据。

比如某件商品库存10件,在一个事务过程中,用户A对该商品下单6件,而另外,用户B也对该商品下单5件,那累加后就超过库存数了,不符合业务要求。所以是,在事务的修改某数据时候,其他的不能修改该数据,但是可以访问该数据,但只能访问到事务开始前的值。这样就是两个进行了隔离。

持久性(Durability)
一个事务一旦提交,他对数据库中数据的改变就应该是永久性的。当事务提交之后,数据会持久化到硬盘,修改是永久性的。

用户如何开启Redis的事务?

事务的执行过程包含3个步骤,Redis提供了MULTI、EXEC两个命令来完成这三个步骤。

  1. 客户端使用 MULTI 命令显式表示开启一个事务
  2. 客户端吧事务中要执行的操作(比如增删改数据)发送给服务端。注意:这些命令虽然被客户端发送到了服务端,但Redis实例只是把这些命令暂存到一个命令队列中,并不会立即执行。
  3. 客户端向服务器发送提交事务的命令 EXEC,让数据库实际执行第二步中发送的具体操作。当服务端收到该命令后,才会真正执行命令队列中的所有命令。

 

使用redis-cli客户端来展示

事务过程中它们执行后的返回结果都是 QUEUED,这就表示,这些操作都被暂存到了命令队列,还没有实际执行。等到执行了 EXEC 命令后,可以看到返回了结果,这就表明,事务中的操作已经成功地执行了。

Go语言编码使用事务

func main() {
	client := redis.NewClient(&redis.Options{
		Addr:     "127.0.0.0.1:6379",
		Password: "", //若是设置了密码,就需要填写
		DB:       0,
	})

	ping, _ := client.Ping().Result()    //测试是否网络通
	fmt.Println(ping)

	//该方法注解//TxPipeline acts like Pipeline, but wraps queued commands with MULTI/EXEC.
	pipe := client.TxPipeline()
	val, _ := pipe.Set("key1", 100, 0).Result()
	fmt.Println("set key1 ", val) //该结果要在执行exec后才会有
	pipe.Set("key2", "200", 0)
	pipe.Get("key2")

	//执行命令队列中的命令
	_, err := pipe.Exec()
	if err != nil {
		fmt.Println(err)
		return
	}
	fmt.Println("执行exec 后 set key1 ", val)

	value1, err := client.Get("key1").Result()
	if err != nil {
		fmt.Println(err)
		return
	}
	fmt.Println("key1: ", value1)
}

Redis 的事务机制能保证哪些属性?

1. 原子性

要求是批操作是全部成功或者全部失败。要是在事务过程中,出现了错误,Redis还能保证原子性吗?这个要分三种情况来分析。

语法错误

语法错误指的是命令的参数个数不正确,命令本身拼写错误等情况。

在执行EXEC命令时,客户端发送的操作命令本身就有错误(比如使用了不存在的命令),在命令入队时候就被Redis判断出来。

在命令入队时候,Redis就会报错并记录下该错误。而此时,我们还能继续提交命令。等到执行EXEC之后,Redis就会拒绝执行所有提交的命令操作,返回错误的结果。

这样,事务中的所有命令都不被执行,保证了原子性。

运行错误

运行错误是指输入的命令格式正确,但是在命令执行期间出现了错误。典型的及时命令和操作的数据类型不服务的情况。比如添加一个string类型的key,之后却对该key进行列表操作。

127.0.0.1:6379> set skey ss
OK
127.0.0.1:6379> lpush skey value
(error) WRONGTYPE Operation against a key holding the wrong kind of value

那么,事务操作入队时候,命令和操作的数据类型不匹配,但是Redis没有检查出错误。但是在执行完EXEC之后,Redis实际执行这些操作时候,会报错。但是,注意:Redis对错误命令报错,但还是会把正确的命令执行完。在这种情况下,事务的原子性就无法得到保证。

127.0.0.1:6379> multi
OK
127.0.0.1:6379(TX)> set score 100
QUEUED
127.0.0.1:6379(TX)> lpush score 200
QUEUED
127.0.0.1:6379(TX)> exec
1) OK
2) (error) WRONGTYPE Operation against a key holding the wrong kind of value

上面的例子,命令和操作的数据类型不匹配的时候,set命令成功了,而lpush失败了。这个事务的原子性就没有得到保证。

DISCARD命令

到这里,你可能会疑惑,传统数据库(比如MySQL)在z执行事务的时候,会提供回滚机制,当事务执行发生错误的时候,事务中的所有操作都会被撤销,已经被修改的数据也会被恢复到事务执行前的状态。那么,在上面的例子中,若命令实际执行时报错了,是不是可以用回滚机制来恢复原来的数据呢?

其实,Redis没有提供回滚机制。Redis提供了DISCARD命令,但是,这个命令只能用来主动放弃事务执行,把暂存的命令队列情况,没起到回滚的效果。

执行EXEC时,Redis发生故障

事务的命令都是放入到一个命令队列中的,那么执行exec时候,执行了该事务的一半命令,而Redis出现故障,那这一半命令是执行成功的了。但是Redis出故障重启后,就需要通过RDB或者AOF文件去恢复数据。

  • AOF模式:现在一般都是开启AOF的,若开启了AOF的, Redis会首先去找AOF文件恢复数据。首先,这个事务的一半命令的操作记录是被记录到AOF日志中的了。但是这个事务是未完成的。使用redis-check-aof工具检测 AOF 日志文件,可以把未完成的事务操作从 AOF 文件中去除。这样一来,使用 AOF 文件恢复实例后,这个事务不会被再执行,从而保证了原子性
  • RDB模式:若是只使用RDB模式,在执行事务时,Redis 不会中断事务去执行保存 RDB 的工作,只有在事务执行之后,保存 RDB 的工作才有可能开始。即是最新的 RDB 快照是在当前 EXEC 执行之前生成的。所以当 RDB 模式下的 Redis 服务器进程在事务中途出故障时,事务内执行的命令,不管成功了多少,都不会被保存到 RDB 文件里。通过RDB文件去恢复,这样就不会再次执行该事务的命令语句,从而保证了原子性。
  • 不开启AOF和RDB:重启后内存中的数据就会全部丢失,也就谈不上原子性了。

Redis对事务原子性属性的保证情况

  • 命令入队时就报错,会放弃事务执行,保证原子性;
  • 命令入队时没有报错,在实际执行时报错,不保证原子性;
  • exec命令执行时,Redis实例故障,若开启了AOF或者RDB,可以保证原子性。

 

 2. 一致性

其会受到错误命令、实例故障的影响。有三种情况:

命令入队就错误

在这种情况下,事务本身就会被放弃执行,那么就可以保证数据库的一致性。

命令在实际执行时才报错

在这种情况下,有错误的命令不会被执行,正确的命令可以正常执行,所以也不会改变数据库的一致性。

EXEC命令执行时,Redis发生故障

故障后进行重启,就会使用RDB或AOF文件来恢复数据。

  • 纯内存模式。即是没有开启RDB或者AOF,,那实例故障重启后,数据就都没有了,数据库是一致的。
  • 使用RDB快照模式。因为RDB快照不会在事务执行时执行,所以,事务命令的操作不会被保存到RDB快照中。使用RDB恢复时候,数据库里的数据也是一样的。
  • 使用AOF。而事务操作还没有被记录到AOF日志时(即是命令已经有执行一条的,当时该记录还没有写入到磁盘中),实例就发生故障。所以使用AOF日志恢复的数据库日志时一致的。若是只有部分操作被记录到了AOF日志,我们可以使用 redis-check-aof 清除事务中已经完成的操作,数据库恢复后也是一致的。

所以,总结来说,在命令执行错误或 Redis 发生故障的情况下,Redis 事务机制对一致性属性是有保证的。

 

3. 隔离性 

这个属性有讲究。一开始时候,我认为Redis的执行命令部分是单线程的,那就是串行化,那肯定是有隔离性保障的。但是却不是这么简单的。

看一个场景,商品库存是10,用户A开启事务,把库存-5的操作存入到命令队列中,这时用户B把库存-5,这个操作是即刻执行的。那在真正执行事务命令前,库存就是3了。之后exec,那库存再-5,那就不符合业务要求的,那就是没有隔离性。

所以, 不是说是单线程执行命令就是有隔离性保证的了。

Redis的隔离性保证,会受到和事务一起执行的并发操作的影响。而事务执行又可以分成 命令入队(exec命令执行前)命令实际执行(exec命令执行后) 两个阶段。

  • 并发操作在exec命令执行前,隔离性的保证要使用watch机制来实现,否则无隔离性(就是上面的例子)。
  • 并发操作在exec命令后,此时,隔离性可以保证。

那要讲讲watch机制。其作用是,在事务真正执行前,监控该事务会操作的一个或多个键的变化情况,当事务调用exec执行时,watch机制会先检查监控的键是否被其他客户端修改了,若是修改了,就放弃事务执行,避免事务的隔离性被破坏。然后,客户可以再次执行事务,若此时没有并发修改数据的操作了,事务就能正常执行,隔离性也得到了保证。

watch机制,对于用户来说,就是使用watch命令,当时需要用户主动显性使用watch监听想要操作的键。比如上面的事务是想要操作键shop,所以就需要在mutli之前执行 watch shop。

执行exec时候,返回nil,表示放弃事务执行。这样一来,事务的隔离性就可以得到保证了。

而另一种情况:并发操作在 EXEC 命令之后被服务器端接收并执行

这个就简单多了。因为Redis执行命令部分是单线程的,而且,exec命令执行后,Redis会保证先把命令队列中的命令执行完,之后才执行并发收到的命令。所以这时并发操作,不会影响到事务命令执行。所以,在该情况下,并发操作并不会破坏事务的隔离性。

 

4. 持久性

Redis是内存数据库,所以,其数据是否持久化保存是完全取决于Redis的持久化配置模式。

  • 没有使用RDB或者AOF,事务的持久性肯定是得不到保证的。
  • 使用RDB模式。在一个事务执行后,下一次的 RDB 快照还未执行前,如果发生了实例宕机,事务的持久性同样无法保证;
  • 使用 AOF 模式。AOF 模式的三种配置选项 no 、everysec 都会存在数据丢失的情况 。always 可以保证事务的持久性,但因为性能太差,在生产环境一般不推荐使用。

综上,redis 事务的持久性是无法保证的 。 

总结

Redis使用 multi、exec、discard、watch 四个命令来支持事务机制。

  • multi :开启一个事务
  • exec :提交事务,从命令队列中取出提交的操作命令,进行实际执行
  • discard : 放弃一个事务,清空命令队列
  • watch :检测一个或多个键的值在事务执行过程中是否发生变化,若发生变化,当前事务就放弃执行

Redis的事务机制可以保证一致性隔离性一定程度的原子性(不提供回滚),无法保证持久性。 

原子性的情况比较复杂,只有当事务中使用的命令执行时有误(即是入队无误,执行时刻有误),原子性得不到保证,其他情况下,事务都可以原子性执行。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

idm下载速度慢解决办法 idm批量下载怎么用 idm优化下载速度 Internet Download Manager解决下载速度慢的方法教程

IDM (Internet Download Manager)是一款兼容性大,支持多种语言的下载管理软件,它可以自动检测并下载网页上的内容,这正是这一优点,使得它受到了广大用户的喜爱。但是在下载的过程中,我们会遇到idm下载速度慢怎么回事&a…

深度学习系列66:试穿模型IDM-VTON上手

1. 模型概述 如图,总体流程为: 输入为:衣服的编码xg;人物noise的编码xt;人物身上衣物的mask和人体pose分割(densepose);衣服部分经过两部分网络:1)高级语义网络IP-Adapter&#xff…

假设检验随想

⭐️ 前言 你会吵架吗?你会用数学吵架吗,不会的话就过来看看吧,哈哈 西方人发明了现代意义上的概率论,于是就想把它推广到生产和生活中。借助一大堆的概率论中的概念,他们发明了假设检验,想利用有限的数据…

Cloudflare高级防御规则 看看我的网站如何用防御的

网站已趋于稳定,并且经过nginx调优。我想先分享一下Cloudflare的WAF规则,因为这是最有效的防御之一,可以抵御大量恶意攻击流量,我已经验证了数月。 对于海外独立站电商网站,Cloudflare的CDN服务是首选,它强…

基于SpringBoot的“在线BLOG网”的设计与实现(源码+数据库+文档+PPT)

基于SpringBoot的“在线BLOG网”的设计与实现(源码数据库文档PPT) 开发语言:Java 数据库:MySQL 技术:SpringBoot 工具:IDEA/Ecilpse、Navicat、Maven 系统展示 在线BLOG网结构功能图 管理员登录功能界面 用户信息…

自动驾驶 | 仿真测试-HiL测试全解析

1.HiL 的定义 HiL(Hardware-in-the-Loop)硬件在环是计算机专业术语,也即是硬件在回路。通过使用 “硬件在环”(HiL) ,可以显著降低开发时间和成本。在过去,开发电气机械元件或系统时,使用计算机仿真和实际的实验就已经…

大长案例 - 通用的三方接口调用方案设计

文章目录 引言身份验证防止重复提交数据完整性和加密回调地址安全事件响应可用性 设计方案概述1. API密钥生成2. 接口鉴权3. 回调地址设置4. 接口API设计 权限划分权限划分概述1. 应用ID(AppID)2. 应用公钥(AppKey)【(…

蒸发式工业冷风机

工业冷风机是一种专为工业环境设计的降温设备,它通过水蒸发吸热的原理来降低环境温度。以下是关于工业冷风机降温的一些详细信息: 降温原理: 工业冷风机(也称为蒸发式冷风机或蒸发式冷却机)利用“水蒸发吸收热量”的物…

Linux基础——Linux开发工具(上)vim

前言:在了解完Linux基本指令和Linux权限后,我们有了足够了能力来学习后面的内容,但是在真正进入Linux之前,我们还得要学会使用Linux中的几个开发工具。而我们主要介绍的是以下几个: yum, vim, gcc / g, gdb, make / ma…

pyqt拖入图片并显示

pyqt拖入图片并显示 介绍效果代码 介绍 像拖入文本一样,把图片拖入到窗体中显示。 效果 代码 import sys from PyQt5.QtWidgets import QApplication, QWidget, QLabel, QVBoxLayout from PyQt5.QtGui import QPixmap, QDragEnterEvent, QDropEvent from PyQt5.Q…

嵌入式C语言教程:使用DMA控制的UART通信

在许多嵌入式系统中,UART(通用异步接收/发送)是一种常见的通信协议,用于低速串行数据传输。 通过DMA(直接内存访问)控制UART通信,可以有效地释放CPU资源,使其能够处理其他计算任务。…

一种基于YOLOv8改进的高精度红外小目标检测算法 (原创自研)

💡💡💡本文摘要:一种基于YOLOv8改进的高精度小目标检测算法, 在红外小目标检测任务中实现暴力涨点; 💡💡💡创新点: 1)SPD-Conv特别是在处理低分…

安防监控/智能分析EasyCVR视频汇聚平台海康/大华/宇视摄像头国标语音GB28181语音对讲配置流程

一、背景分析 近年来,国内视频监控应用发展迅猛,系统接入规模不断扩大,涌现了大量平台提供商,平台提供商的接入协议各不相同,终端制造商需要给每款终端维护提供各种不同平台的软件版本,造成了极大的资源浪…

Flask 3 保姆级教程(一):快速上手

一、创建项目 PyCharm 中新建项目 创建完成后会出现这么个项目 以下是代码解析: # 导入了 Flask 类 from flask import Flask# 创建了一个 Flask web 应用的实例,并将其赋值给变量 app # __name__ 是一个特殊的 Python 变量,它表示当前模块…

conda env list找不到anaconda/envs下的环境。Could not find conda environment。

home/用户名/anaconda3/envs中的环境与conda env list下显示的环境不一致。 想进入home/用户名/anaconda3/envs中的环境,显示环境不存在。 重点!!!(conda activate 环境地址 可进入环境) 这一步最重要&…

springboot mongodb分片集群事务

前置 mongodb分片集群想要使用事务,需要对应分片没有仲裁节点 代码 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-mongodb</artifactId><version>2.1.0.RELEASE</version></d…

解决NetworkManager覆盖/etc/resolv.conf的问题

发布时间&#xff1a;2024.4.27 问题 /etc/resolv.conf是Linux下DNS的配置文件。 但是NetworkManager会用覆盖它&#xff0c;导致我们每次都要重新配置。 解决办法 这是官方推荐的做法。或者你可以用resolveconf工具。 $ nm-connection-editor会调起一个界面&#xff0c;…

AI视频教程下载:用ChatGPT提示词开发AI应用和GPTs

在这个课程中&#xff0c;你将深入ChatGPT的迷人世界&#xff0c;学习如何利用其能力构建创新和有影响力的工具。你将发现如何创建不仅吸引而且保持用户参与度的应用程序&#xff0c;将流量驱动到你的网站&#xff0c;并开辟新的货币化途径。 **课程的主要特点&#xff1a;** …

聊聊Mysql的两阶段提交

从图中可看出&#xff0c;事务的提交过程有两个阶段&#xff0c;就是将 redo log 的写入拆成了两个步骤&#xff1a;prepare 和 commit&#xff0c;中间再穿插写入bin log&#xff0c;具体如下&#xff1a; prepare 阶段&#xff1a;将 事务的修改写入到 redo log&#xff0c;同…

软件测试的内容包含什么内容

软件测试的内容涵盖了多个方面&#xff0c;以确保软件的质量和性能达到既定的标准。这些内容包括但不限于以下几点&#xff1a; 注册信息验证&#xff1a;对软件产品的基本信息进行验证&#xff0c;如软件名称、版本号、开发者等&#xff0c;确保这些信息的准确性和一致性。功…
最新文章