Redis系列之事务

概述

Redis事务提供一种将多个命令打包,然后一次性、按顺序地执行的机制,在事务执行的期间不会主动中断,服务器在执行完事务中的所有命令之后,才会继续处理其他客户端的其他命令。

三个重要的保证:

  • 批量操作在发送EXEC命令前被放入队列缓存
  • 收到EXEC命令后进入事务执行,事务中任意命令执行失败,其余的命令依然被执行
  • 在事务执行过程,其他客户端提交的命令请求不会插入到事务执行命令序列中

Redis中的事务是一组命令的集合,事务也是Redis最小的执行单位,一个事务中的命令要么都执行,要么都不执行。

Redis事务由5个命令来实现:

  1. MULTI:标记一个事务块的开始。开启Redis事务,置客户端为事务态
  2. EXEC:提交事务,执行从MULTI到此命令前的命令队列,置客户端为非事务态
  3. DISCARD:取消事务,置客户端为非事务态
  4. WATCH:监视键值对,作用时如果事务提交EXEC时发现监视的监视对发生变化,事务将被取消
  5. UNWATCH:取消WATCH命令对所有Key的监视

事务从开始到执行会经历以下三个阶段:

  • 开始事务
  • 命令入队
  • 执行事务

MULTI标记事务的开始,将客户端状态的flags属性的REDIS_MULTI选项打开,让客户端从非事务状态切换到事务状态。

命令入队

Redis客户端处理非事务状态时,命令会立即被服务端执行。但是事务状态下,如果客户端发送的命令是上面四个命令其一,则服务器立即执行;除此之外,服务器并不立即执行命令,而是将命令放入事务队列里面,向客户端返回QUEUED回复。
在这里插入图片描述

WATCH

Redis使用WATCH命令监视给定的Key,当EXEC时如果监视的Key从调用WATCH后发生过变化,则整个事务会失败。也可以调用WATCH多次监视多个Key,这样就可以对指定的Key加乐观锁。注意WATCH的Key是对整个连接有效的,事务也一样。如果连接断开,监视和事务都会被自动清除。当然EXEC,DISCARD,UNWATCH命令都会清除连接中的所有监视。

实战

本文使用的Redis版本为Windows下7.4.0版本。

empty array

执行MULTI命令后没有其他命令,直接输入EXEC命令,不报错:

127.0.0.1:6379> multi
OK
127.0.0.1:6379(TX)> exec
(empty array)

WATCH

可用于实现类似于乐观锁效果,即CAS,compare and set。

WATCH用于监视Key是否被改动过,支持同时监视多个Key,只要还没真正触发事务,WATCH都会尽职尽责的监视。当多个线程更新同一个Key值时,会跟原值做比较,一旦发现它被修改过,则拒绝执行命令,执行EXEC时就会返回nil,表示事务无法触发。

双击redis-cli.exe打开一个命令行窗口,依次执行如下命令:

127.0.0.1:6379> watch age
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379(TX)> set age 31
QUEUED

双击redis-cli.exe打开另一个命令行窗口,执行如下命令:

127.0.0.1:6379> set age 32
OK

回到第一个窗口(客户端),提交EXEC命令:

127.0.0.1:6379(TX)> exec
(nil)

命令返回(nil),表示事务无法触发。因为另外一个客户端通过set命令更新过Key

哪怕是值不变,有过set key动作就会更新更新时间戳字段(猜测),和MVCC机制比较类似,Redis源码待调研。

客户端一执行:

127.0.0.1:6379> set age 11
OK
127.0.0.1:6379> watch age
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379(TX)> set age 12
QUEUED

客户端二执行:

127.0.0.1:6379> get age
"11" # 在客户端一执行set后,可get获取
127.0.0.1:6379> set age 11
OK # 在客户端一执行watch后,尝试set更新到相同的年龄

客户端一执行:

127.0.0.1:6379(TX)> exec
(nil)

执行结果也是(nil)。

事务错误

两类错误:

  • 调用EXEC之前的错误
  • 调用EXEC之后的错误

EXEC执行前出错:如语法有误,内存不足导致。只要出现某个命令无法成功写入缓冲队列的情况,Redis都会进行记录,在客户端调用EXEC时,Redis会拒绝执行这一事务。

127.0.0.1:6379> multi
OK
127.0.0.1:6379(TX)> he
(error) ERR unknown command 'he', with args beginning with:
127.0.0.1:6379(TX)> set he he
QUEUED
127.0.0.1:6379(TX)> exec
(error) EXECABORT Transaction discarded because of previous errors.

EXEC执行后出错:Redis不会理睬这些错误,而是继续向下执行事务中的其他命令。对于应用层面的错误,并不是Redis需要考虑和处理的问题,所以事务中如果某一条命令执行失败,并不会影响接下来的其他命令的执行。

127.0.0.1:6379> multi
OK
127.0.0.1:6379(TX)> set age 34
QUEUED
127.0.0.1:6379(TX)> sadd age 35
QUEUED
127.0.0.1:6379(TX)> set age 35
QUEUED
127.0.0.1:6379(TX)> exec
1) OK
2) (error) WRONGTYPE Operation against a key holding the wrong kind of value
3) OK
(0.53s)
127.0.0.1:6379> get age
"35"

这里可以得出一个很重要的结论:在执行事务时某个命令执行失败,并不会影响其他命令的执行,即Redis 的事务并不会回滚。

Lua集成

Lua脚本集成,参考Redis系列之Lua脚本整合。

ACID

传统事务四个核心特性,即ACID。为了保持简单,Redis事务保证其中的一致性和隔离性;不满足原子性和持久性;

原子性

在执行事务命令时,在命令入队时,Redis检测事务里的命令是否正确,即是否有语法错误,如果不正确则会产生错误。事务里的命令是批量提交执行的,也就是命令还没执行,当然也就不存在回滚一说;

当命令格式正确,而因为操作数据结构引起的错误,则该命令执行时才会出现错误,而其之前和之后的命令都会被正常执行。

参考You Don’t Need Transaction Rollbacks in Redis,以及Redis Transactions:

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

翻译:支持回滚会对 Redis 的简单性和性能产生重大影响。

一致性

一致性指的就是事务执行前后的数据符合数据库的定义和要求。

Redis符合要求,不论是发生语法错误还是运行时错误,错误的命令均不会被执行。

隔离性

多个事务并发执行,各个事务之间不会互相影响。原因:Redis事务不会中断,且是单线程执行事务。

持久性

对于事务的执行来说,如果Redis开启AOF持久化,那么一旦事务被成功执行,事务中的命令就会通过write命令一次性写到磁盘中去,如果在向磁盘中写的过程中恰好出现断电、硬件故障等问题,可能出现只有部分命令进行AOF持久化,这时AOF文件就会出现不完整的情况,这时可使用redis-check-aof工具将AOF文件中不完整的信息移除,确保AOF文件完整可用。

原理

Redis中每个客户端都有记录当前客户端的事务状态multiState,客户端client定义,在server.h源码里:

typedef struct client {uint64_t id; // 客户端唯一idmultiState mstate; // MULTI和EXEC状态(即事务状态)// 省略其他属性
} client;

multiState定义如下:

typedef struct multiState {multiCmd *commands; // 存储命令的FIFO队列int count; // 命令总数// 省略其他属性
} multiState;

multiCmd是一个队列,用来接收并存储开启事务之后发送的命令,定义如下:

typedef struct multiCmd {robj **argv; // 用来存储参数的数组int argv_len; // 数组长度int argc; // 参数的数量struct redisCommand *cmd; // 命令指针
} multiCmd;

类结构图:
在这里插入图片描述

拓展

Redis事务在真实业务场景中的应用

  • 批量操作:如果你需要对多个键进行原子性修改,Redis事务可以确保这些操作在没有被中断的情况下执行。例如,批量更新用户积分、库存等;
  • 乐观锁场景:在高并发环境下,使用WATCH可以监控某些关键键的变化,防止并发修改带来的数据不一致问题;
  • 复杂多键操作:在需要对多个键进行依赖性操作时,比如从一个账户扣款同时向另一个账户转账,Redis事务可以确保这类操作的完整性。

局限性:

  • 缺乏回滚机制:如果事务中的某个命令执行失败,Redis不会回滚已经执行的命令,这在某些需要严格数据一致性的场景中是个问题;
  • 命令执行顺序无法调整:事务中的命令执行顺序是固定的,无法在运行时调整,如果某些条件改变,无法动态改变执行顺序;
  • 性能开销:由于事务的执行需要在内存中排队,如果队列中的命令较多,可能导致阻塞和性能问题。

参考

  • Redis事务
  • Redis事务

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

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

相关文章

[Algorithm][贪心][跳跃游戏][加油站][单调递增的数字][坏了的计算器]详细讲解

目录 1.跳跃游戏1.题目链接2.算法思路详解3.代码实现 2.加油站1.题目链接2.算法原理详解3.代码实现 3.单调递增的数字1.题目链接2.算法原理详解3.代码实现 4.坏了的计算器1.代码实现2.算法原理详解3.代码实现 1.跳跃游戏 1.题目链接 跳跃游戏 2.算法思路详解 贪心&#xff1…

WPF—资源的使用

资源的使用 资源是可以在应用中的不同位置重复使用的对象。 资源的示例包括画笔和样式。 <Window.Resources><!--定义颜色资源--><SolidColorBrush x:Key"MyBrush" Color"#05E0E9"/><!--定义样式资源--><Style TargetType&quo…

uniapp在线视频监控开发

我这里是uniapp开发的H5项目 视频流是flv模式 用到的插件是flv.js Flv.js Flv.js 是 HTML5 Flash 视频&#xff08;FLV&#xff09;播放器&#xff0c;纯原生 JavaScript 开发&#xff0c;没有用到 Flash。。由 bilibili 网站开源。 常见直播协议 RTMP: 底层基于TCP&…

TinyVision 使用 SyterKit 启动 Linux 6.7 主线内核

TinyVision 使用 SyterKit 启动 Linux 6.7 主线内核 SyterKit SyterKit 是一个纯裸机框架&#xff0c;用于 TinyVision 或者其他 v851se/v851s/v851s3/v853 等芯片的开发板&#xff0c;SyterKit 使用 CMake 作为构建系统构建&#xff0c;支持多种应用与多种外设驱动。同时 Sy…

docker GBase 8sV8.8使用的常见错误

因项目需要GBase 8sV8.8数据库环境&#xff0c;所以在搭建使用过程中有一些坑和错误&#xff0c;所以记录和分享 docker搭建 docker.com获取镜像 docker pull liaosnet/gbase8s:v8.8_3503x1_x64创建容器 docker run -d -p 19088:9088 \-e SERVERNAMEgbase01 \-e USERPASSGB…

Linux 基础命令大全

Linux是一个功能强大、灵活的操作系统&#xff0c;为用户提供了稳定性、安全性和庞大的开发者和用户社区。它是个人和企业使用的流行选择。 当涉及到Linux基础命令时&#xff0c;以下是一些常用的命令及其功能介绍&#xff1a; 1.ls 查看目录 语法&#xff1a;ls [选项] [文件…

C#实现数据采集系统-数据反写(3)ModbusTcp写入数据模块开发

写入报文分析 ModbusTcp报文详细解析见 ModbusTCP协议报文解析 写入常用的四个功能码&#xff0c;线圈 05,15&#xff08;0x0F&#xff09;,寄存器06,16&#xff08;0x10&#xff09; 详细报文如下&#xff1a; //00 01 00 00 00 06 FF 05 00 01 FF 00 写单个线圈 //00 01 …

PHPStorm如何使用Phalcon框架的依赖

问题背景 在上一篇文章里面写的如何把Phalcon 集成到PhpStorm里面,发现有个地方讲得不是很清楚,就是在使用Phalcon开发的过程中,会发现没有Phalcon框架的代码提示,这个让人感到很难受,写代码的效率也会降低不少。当时讲得是在项目的外部库下导入依赖源, 然后在写代码的时…

HTML简单了解和基础知识记录

参考视频 html的用途 超文本标记语言&#xff08;英语&#xff1a;HyperText Markup Language&#xff0c;简称&#xff1a;HTML&#xff09;&#xff0c;用来显示网页的文字和框架结构&#xff0c;可以认为是网页的骨架。 标签/元素 用于定义文字图片连接等&#xff0c;分…

R 语言学习教程,从入门到精通,R 绘图饼图(23)

1、R 绘图 条形图 条形图&#xff0c;也称为柱状图条形图&#xff0c;是一种以长方形的长度为变量的统计图表。 条形图可以是水平或垂直的&#xff0c;每个长方形可以有不同的颜色。 R 语言使用 barplot() 函数来创建条形图&#xff0c;格式如下&#xff1a; barplot(H,xlab,…

JavaScript初级——DOM和事件简介

一、什么是DOM&#xff1f; 二、模型 三、对象的 HTML DOM 树 四、节点 浏览器已经为我们提供了文档节点对象&#xff0c;这个对象是window属性&#xff0c;可以再网页中直接使用&#xff0c;文档节点代表的是整个网页。 五、事件简介 事件&#xff0c;就是用户和浏览器之间的交…

Linux系统下的容器安全:深入解析与最佳实践

在云计算和微服务架构的推动下&#xff0c;容器技术因其高效、可移植和灵活的特点&#xff0c;已经成为现代软件开发和部署的首选方案。然而&#xff0c;容器的广泛应用也带来了新的安全挑战&#xff0c;尤其是在Linux系统下&#xff0c;容器安全的实现和维护变得尤为重要。本文…

C++ 设计模式——单例模式

单例模式 C 设计模式——单例模式1. 单例模式的基本概念与实现2. 多线程环境中的问题3. 内存管理问题1. 内存泄漏风险2. 自动释放策略3. 垃圾回收机制4. 嵌套类与内存管理 4. UML 图UML 图解析 优缺点适用场景总结 C 设计模式——单例模式 单例模式&#xff08;Singleton Patt…

【Redis】渐进式遍历和数据库管理

渐进式遍历和数据库管理 渐进式遍历scan 数据库管理切换数据库清除数据库 渐进式遍历 Redis 使⽤ scan 命令进⾏渐进式遍历键&#xff0c;进⽽解决直接使⽤ keys 获取键时可能出现的阻塞问题。每次 scan 命令的时间复杂度是 O(1)&#xff0c;但是要完整地完成所有键的遍历&…

360发布FancyVideo:通过跨帧文本指导实现动态且一致的视频生成SOTA!

文章链接&#xff1a;https://arxiv.org/pdf/2408.08189 项目链接&#xff1a;https://360cvgroup.github.io/FancyVideo/ 亮点直击 本文介绍了FancyVideo&#xff0c;据众所知的首个探索T2V任务中跨帧文本指导的开创性尝试。该方法为增强当前的文本控制方法提供了新的视角。 …

EmguCV学习笔记 VB.Net 6.5 凸包和凸缺陷

版权声明&#xff1a;本文为博主原创文章&#xff0c;转载请在显著位置标明本文出处以及作者网名&#xff0c;未经作者允许不得用于商业目的。 EmguCV是一个基于OpenCV的开源免费的跨平台计算机视觉库,它向C#和VB.NET开发者提供了OpenCV库的大部分功能。 教程VB.net版本请访问…

OpenCV c++ 实现图像马赛克效果

VS2022配置OpenCV环境 关于OpenCV在VS2022上配置的教程可以参考&#xff1a;VS2022 配置OpenCV开发环境详细教程 图像马赛克 图像马赛克&#xff08;Image Mosaic&#xff09;的原理基于将图像的特定区域替换为像素块&#xff0c;这些像素块可以是纯色或者平均色&#xff0c…

SpringMVC核心机制环境搭建

文章目录 1.SpringMVC执行流程1.基础流程图2.详细流程图 2.安装Tomcat1.下载2.解压到任意目录即可3.IDEA配置Tomcat1.配置Deloyment2.配置Server 3.创建maven项目1.创建sun-springmvc模块&#xff08;webapp&#xff09;2.查看是否被父模块管理3.pom.xml引入依赖4.目录5.SunDis…

【Redis】Redis数据结构——Hash 哈希

哈希 命令hsethgethexistshdelhkeyshvalshgetallhmgethlenhsetnxhincrbyhincrbyfloat命令小结 内部编码使用场景缓存⽅式对⽐ ⼏乎所有的主流编程语⾔都提供了哈希&#xff08;hash&#xff09;类型&#xff0c;它们的叫法可能是哈希、字典、关联数组、映射。在 Redis 中&#…

C语言函数介绍(上)

函数概念库函数标准库和头文件库函数的使用方法头文件包含库函数文档的一般格式 自定义函数函数的语法形式函数例子 形参和实参实参形参实参和形参的关系 return 语句数组做函数参数 函数概念 数学中我们其实就见过函数的概念&#xff0c;比如&#xff1a;一次函数 ykxb &…