怎么理解 Redis 事务
背景
在面试中经常会被问到,redis支持事务吗?事务是怎么实现的?事务会回滚吗?又是一键三连,我下面分析下,看看能不能吊打面试官
什么是Redis事务
- 事务是一个单独的隔离操作:事务中的所有命令都会序列化、按顺序地执行。 事务在执行的过程中,不会被其他客户端发送来的命令请求所打断。
- 事务是一个原子操作:事务中的命令要么全部被执行,要么全部都不执行。
总结说:redis事务就是一次性、顺序性、排他性的执行一个队列中的一系列命令。
Redis 中的事务如何工作
Redis 事务允许在一个步骤中执行一组命令,它们以 MULTI、EXEC、DISCARD 和 WATCH 命令为中心,事务中的所有命令都被序列化并按顺序执行。另一个客户端发送的请求永远不会在 Redis 事务执行过程中得到服务。这保证了命令作为单个独立操作执行。
一个事务从开始到执行会经历以下三个阶段:
- 开启事务。
- 命令入队。
- 执行事务或者放弃事务。
其中,开启事务使用 multi 命令,事务执行使用 exec 命令,放弃事务使用 discard 命令。
事务执行流程图,可以直观的看下:
Redis事务相关命令和使用
- MULTI :开启事务,redis会将后续的命令逐个放入队列中,然后使用EXEC命令来原子化执行这个命令系列。
- EXEC:执行事务中的所有操作命令。
- DISCARD:取消事务,放弃执行事务块中的所有命令。
- WATCH:监视一个或多个key,如果事务在执行前,这个key(或多个key)被其他命令修改,则事务被中断,不会执行事务中的任何命令。
- UNWATCH:取消WATCH对所有key的监视。
MULTI 开启事务
multi 命令用于开启事务,实现代码如下:
# multi 命令可以让客户端从非事务模式状态,变为事务模式状态
127.0.0.1:6371> MULTI
OK
注意啊:multi 命令不能嵌套使用,如果已经开启了事务的情况下,再执行 multi 命令,会提示如下错误:
127.0.0.1:6371> MULTI
OK
127.0.0.1:6371(TX)> MULTI
(error) ERR MULTI calls can not be nested
命令入列
客户端进入事务状态之后,执行的所有常规 Redis 操作命令(非触发事务执行或放弃和导致入列异常的命令)会依次入列,命令入列成功后会返回 QUEUED,如下代码所示
127.0.0.1:6371> MULTI
OK
127.0.0.1:6371(TX)> set k 1
QUEUED
127.0.0.1:6371(TX)> set b 1
QUEUED
用户可以发出多个命令,命令会按照先进先出(FIFO)的顺序出入列,Redis 不会执行这些命令,而是将它们排队。需要调用 EXEC执行事务 ,所有命令才会执行。
执行事务/放弃事务
执行事务的命令是 exec,放弃事务的命令是 discard。
执行事务:
127.0.0.1:6371> MULTI
OK
127.0.0.1:6371(TX)> set k 1
QUEUED
127.0.0.1:6371(TX)> set b 1
QUEUED
127.0.0.1:6371(TX)> EXEC
1) OK
2) OK
EXEC 返回一个回复数组,其中每个元素都是事务中单个命令的回复,与发出命令的顺序相同。
放弃事务:
127.0.0.1:6371> MULTI
OK
127.0.0.1:6371(TX)> set k 2
QUEUED
127.0.0.1:6371(TX)> set b 2
QUEUED
127.0.0.1:6371(TX)> DISCARD
OK
127.0.0.1:6371> get k
"1"
127.0.0.1:6371> get b
"1"
MULTI开启事务后,命令入队,取消事务,队列里面的命令是不会执行的。 设置 k、b两个key的值为2,取消事务后,值还是保留以前是 1,说明取消事务后,队列里面的命令没有执行
事务出现错误的处理
事务执行中的错误分为以下两类:
- 入列的命令语法错误,终止事务
- 入列命令运行时错误,不会终止事务
入列的命令语法错误,终止事务
分别设置 k1、k2的值为1,然后开启事务,设置值k1、k2的值为2,其中 设置k2的时候 命令出错 sets,执行事务,入列的命令未执行,终止了事务
127.0.0.1:6371> set k1 1
OK
127.0.0.1:6371> set k2 1
OK
127.0.0.1:6371> get k1
"1"
127.0.0.1:6371> get k2
"1"
127.0.0.1:6371> MULTI
OK
127.0.0.1:6371(TX)> set k1 2
QUEUED
127.0.0.1:6371(TX)> sets k2 2
(error) ERR unknown command 'sets', with args beginning with: 'k2' '2'
127.0.0.1:6371(TX)> EXEC
(error) EXECABORT Transaction discarded because of previous errors.
127.0.0.1:6371> get k1
"1"
127.0.0.1:6371> get k2
"1"
入列的命令运行时错误,不会终止事务
在开启事务后,修改k1值为2,但将k2的类型作为List,进行元素操作,在运行时检测类型错误,最终导致事务提交失败,此时事务并没有回滚,而是跳过错误命令继续执行, 结果k1值改变
127.0.0.1:6371> get k1
"1"
127.0.0.1:6371> get k2
"1"
127.0.0.1:6371> MULTI
OK
127.0.0.1:6371(TX)> set k1 2
QUEUED
127.0.0.1:6371(TX)> LPOP k2
QUEUED
127.0.0.1:6371(TX)> exec
1) OK
2) (error) WRONGTYPE Operation against a key holding the wrong kind of value
127.0.0.1:6371> get k1
"2"
运行时发生错误,事务未终止,事务不会回滚呢?
为什么事务不会回滚?
Redis 官方文档的解释如下:
Redis 命令只会因为错误的语法而失败(并且这些问题不能在入队时发现),或是命令用在了错误类型的键上面:这也就是说,从实用性的角度来说,失败的命令是由编程错误造成的,而这些错误应该在开发的过程中被发现,而不应该出现在生产环境中。
watch 监控
WATCH 用于为 Redis 事务提供检查和设置 (CAS) 行为。
watch 命令用于客户端并发情况下,为事务提供一个乐观锁(CAS,Check And Set),也就是可以用 watch 命令来监控一个或多个变量,如果在事务的过程中,某个监控项被修改了,那么整个事务就会终止执行,并且 EXEC 返回 Null 回复以通知事务失败
watch 基本语法如下:
watch key [key ...]
举个例子,看下修改监控的key以后,事务是否会终止
客户端1:设置k1的值为1,k2的值1,然后 watch 监控k1,开启事务,设置k1为2,k2为2,客户端2:修改k1的值为23,客户端1执行事务
客户端1执行命令如下:
127.0.0.1:6371> set k1 1
OK
127.0.0.1:6371> set k2 1
OK
127.0.0.1:6371> WATCH k1
OK
127.0.0.1:6371> MULTI
OK
127.0.0.1:6371(TX)> set k1 2
QUEUED
127.0.0.1:6371(TX)> set k2 2
QUEUED
127.0.0.1:6371(TX)> EXEC
(nil)
127.0.0.1:6371> get k1
"3"
127.0.0.1:6371> get k2
"1"
客户端2执行命令如下:
127.0.0.1:6371> set k1 3
OK
从上面的结果可以看出,监控了k1,客户端2修改了k1的值,事务是中止的
如果不再监控key,使用UNWATCH 取消监控
代码实现
使用jedis客户端实现,代码如下:
public static void main(String[] args) {Jedis jedis = new Jedis("10.1.250.157", 6379);jedis.auth("google00");jedis.set("k","1");//监控keyjedis.watch("k");//开启事务Transaction tx =jedis.multi();// 命令入队tx.set("k","2");tx.set("k1","3");//执行事务tx.exec();//取消监控jedis.unwatch();}
总结
redis是支持事务的,开启事务后,命令入队,命令的语法如果有错,执行事务会中止,如果执行命令的时候发现命令有问题,其他命令能正常执行,事务是不会回滚的,因为redis的回滚会对redis的简单性和性能造成严重影响。
特别注意: 事务中的命令要么全部被执行,要么全部都不执行 。是执行,不是成功哦,更我们平时用的关系型数据库是有差别的。
相关文章:

怎么理解 Redis 事务
背景 在面试中经常会被问到,redis支持事务吗?事务是怎么实现的?事务会回滚吗?又是一键三连,我下面分析下,看看能不能吊打面试官 什么是Redis事务 事务是一个单独的隔离操作:事务中的所有命令…...
react中的diff算法
diff算法 对于React团队发现在日常开发中对于更新组件的频率,会比新增和删除的频率更高,所以在diff算法里,判断更新的优先级会更高。对于Vue2的diff算法使用了双指针,React的diff算法没有使用双指针,是因为更新的jsx对…...

【医学大模型 尘肺病】PneumoLLM:少样本大模型诊断尘肺病新方法
PneumoLLM:少样本大模型诊断尘肺病新方法 提出背景PneumoLLM 框架效果 提出背景 论文:https://arxiv.org/pdf/2312.03490.pdf 代码:https://github.com/CodeMonsterPHD/PneumoLLM/tree/main 历史问题及其背景: 数据稀缺性问题&a…...

【SpringBootStarter】自定义全局加解密组件
【SpringBootStarter】 目的 了解SpringBoot Starter相关概念以及开发流程实现自定义SpringBoot Starter(全局加解密)了解测试流程优化 最终引用的效果: <dependency><groupId>com.xbhog</groupId><artifactId>globalValidation-spring…...

【射影几何15】python双曲几何工具geometry_tools
目录 一、说明二、环境问题:如何安装三、实现一个简单的例子四、绘制双曲组五、使用有限状态自动机加快速度六、资源和代码 一、说明 Geometry_tools 是一个 Python 包,旨在帮助您处理和可视化双曲空间和射影空间上的群动作。 该包主要构建在 numpy、…...
机器人抓取 [ 题目/摘要 ] 更新中..
题目:Robotic Grasping of Novel Objects using Visionl 链接:机器人抓取新物体 | IEEE Xplore(IEEE的Xplore) 【端到端】 摘要:我们考虑抓取新物体的问题,特别是第一次通过视觉看到的物体。抓取以前未知的…...

【51单片机】外部中断和定时器中断
目录 中断系统中断介绍中断概念 中断结构及相关寄存器中断结构中断相关寄存器 外部中断实验外部中断配置软件设计实验现象 定时器中断定时器介绍51 单片机定时器原理51 单片机定时/计数器结构51 单片机定时/计数器的工作方式 定时器配置硬件设计软件设计实验现象 中断系统 本章…...

零售行业供应商数据分发,怎样提高安全性和效率?
零售行业是我国经济发展的重要组成,零售行业包罗万象,如包括汽车零售、日化零售、快消品零售等,不同细分行业的运营模式各不相同,但大体来说,零售行业都具备最基础的供应商和零售商,供应商将商品或服务卖给…...

Windows下Node.js下载安装及环境变量配置教程
Windows下Node.js下载安装及环境变量配置教程 安装版本:node-v18.19.0-x64.msi 文章目录 Windows下Node.js下载安装及环境变量配置教程一、Node.js和NPM简介二、下载地址三、安装步骤四、环境配置五、安装淘宝镜像总结 一、Node.js和NPM简介 1、Node.js …...
广义表-C语言
广义表(Generalized List)是一种扩展了线性表的数据结构,它在线性表的基础上增加了元素可以是表的特点。在广义表中,元素不仅可以是单个的数据元素,还可以是一个子表,而子表中的元素也可以是数据元素或其他…...

uniapp+uView 【详解】录音,自制音频播放器
效果预览 代码实现 <template><view class"btnListBox"><view class"audioBox" v-if"audioLength"><u-row><u-col span"2"><u--text aligncenter :text"currentTime"></u--text>…...

机器学习---概率图模型(隐马尔可夫模型、马尔可夫随机场、条件随机场)
1. 隐马尔可夫模型 机器学习最重要的任务是根据已观察到的证据(例如训练样本)对感兴趣的未知变量(例如类别标 记)进行估计和推测。概率模型(probabilistic model)提供了一种描述框架,将描述任…...
cool 框架 node 后端封装三方Api post请求函数
1.需求 现在一些数据源 ,需要从三方地址拿到一些数据 比如说电影列表 信息了 影院列表信息了 等一些展示的数据,但是人家这种东西 害需要使用 appkey appserect 这种验签 这种需求 你前端调用接口是直接调用不了的 因为需要用到验签 需要后端接口转接一…...

awd总结
总结: 由于是第一次参加AWD比赛,各方面经验都不足,在参赛的前几天也是疯狂搜集各种脚本、框架、工具等,同时也参考b站的视频进行学习,我发现就是还是实操才能更快的学习 我觉得就是我前期的准备工作不足,…...
【react】react+es6+antd5.13.2+ts,antd表格的操作如何在父组件写?
reactes6antd5.13.2ts,antd表格的操作如何在父组件写? 我的子组件columns.tsx,只加表头,操作放在父组件。 columns.tsx的代码: export const dataColumns [{title: 项目成员,dataIndex: name,key: name,},{title: 可选账号,alig…...
virtio笔记
最近在看虚拟化相关的东西,以virtio-console为例,记录下。 此文只是学习笔记,文中肯定有不少错误,不要参考 devicemd侧: virtio_console.c中,初始化会对port->cb赋值为 viritio_console_control_tx&am…...

初始web服务器(并基于idea来实现无需下载的tomcat)
前言 前面学习了对应的http协议,我们知道了他是在网络层进行数据传输的协议,负责相应数据以及接收数据的规则,但是在人员开发后端的时候不仅仅需要你写io流进行数据传输,还需要你进行对应的tcp协议来进行数据打包发送http协议-CSD…...

软件文档测试
1 文档测试的范围 软件产品由可运行的程序、数据和文档组成。文档是软件的一个重要组成部分。 在软件的整人生命周期中,会用到许多文档,在各个阶段中以文档作为前阶段工作成果的体现和后阶段工作的依据。 软件文档的分类结构图如下图所示: …...

从零开始手写mmo游戏从框架到爆炸(七)— 消息封装
导航:从零开始手写mmo游戏从框架到爆炸(零)—— 导航-CSDN博客 上一篇,我们初步把消息handler 注册到了服务中,在进行后续工作之前我们需要再做一些准备工作。 第一:把之前自己管理的bean放到spring中…...
从Unity到Three.js(画线组件line)
JavaScript 0基础,只是照着官方文档临摹了下,之后有时间再进行细节学习和功能封装。 import * as THREE from three; //引入threejsconst renderer new THREE.WebGLRenderer();//创建渲染器 //设置渲染范围,当前撑满全屏,屏幕左上角是&…...

AI Agent与Agentic AI:原理、应用、挑战与未来展望
文章目录 一、引言二、AI Agent与Agentic AI的兴起2.1 技术契机与生态成熟2.2 Agent的定义与特征2.3 Agent的发展历程 三、AI Agent的核心技术栈解密3.1 感知模块代码示例:使用Python和OpenCV进行图像识别 3.2 认知与决策模块代码示例:使用OpenAI GPT-3进…...
Java如何权衡是使用无序的数组还是有序的数组
在 Java 中,选择有序数组还是无序数组取决于具体场景的性能需求与操作特点。以下是关键权衡因素及决策指南: ⚖️ 核心权衡维度 维度有序数组无序数组查询性能二分查找 O(log n) ✅线性扫描 O(n) ❌插入/删除需移位维护顺序 O(n) ❌直接操作尾部 O(1) ✅内存开销与无序数组相…...

从深圳崛起的“机器之眼”:赴港乐动机器人的万亿赛道赶考路
进入2025年以来,尽管围绕人形机器人、具身智能等机器人赛道的质疑声不断,但全球市场热度依然高涨,入局者持续增加。 以国内市场为例,天眼查专业版数据显示,截至5月底,我国现存在业、存续状态的机器人相关企…...

抖音增长新引擎:品融电商,一站式全案代运营领跑者
抖音增长新引擎:品融电商,一站式全案代运营领跑者 在抖音这个日活超7亿的流量汪洋中,品牌如何破浪前行?自建团队成本高、效果难控;碎片化运营又难成合力——这正是许多企业面临的增长困局。品融电商以「抖音全案代运营…...
【算法训练营Day07】字符串part1
文章目录 反转字符串反转字符串II替换数字 反转字符串 题目链接:344. 反转字符串 双指针法,两个指针的元素直接调转即可 class Solution {public void reverseString(char[] s) {int head 0;int end s.length - 1;while(head < end) {char temp …...

[10-3]软件I2C读写MPU6050 江协科技学习笔记(16个知识点)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16...

微服务商城-商品微服务
数据表 CREATE TABLE product (id bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 商品id,cateid smallint(6) UNSIGNED NOT NULL DEFAULT 0 COMMENT 类别Id,name varchar(100) NOT NULL DEFAULT COMMENT 商品名称,subtitle varchar(200) NOT NULL DEFAULT COMMENT 商…...
Spring AI与Spring Modulith核心技术解析
Spring AI核心架构解析 Spring AI(https://spring.io/projects/spring-ai)作为Spring生态中的AI集成框架,其核心设计理念是通过模块化架构降低AI应用的开发复杂度。与Python生态中的LangChain/LlamaIndex等工具类似,但特别为多语…...

以光量子为例,详解量子获取方式
光量子技术获取量子比特可在室温下进行。该方式有望通过与名为硅光子学(silicon photonics)的光波导(optical waveguide)芯片制造技术和光纤等光通信技术相结合来实现量子计算机。量子力学中,光既是波又是粒子。光子本…...
4. TypeScript 类型推断与类型组合
一、类型推断 (一) 什么是类型推断 TypeScript 的类型推断会根据变量、函数返回值、对象和数组的赋值和使用方式,自动确定它们的类型。 这一特性减少了显式类型注解的需要,在保持类型安全的同时简化了代码。通过分析上下文和初始值,TypeSc…...