Redis入门第三步:Redis事务处理

news2024/12/25 2:18:49

在这里插入图片描述

欢迎继续跟随《Redis新手指南:从入门到精通》专栏的步伐!在本文中,我们将探讨Redis的事务处理机制。了解如何使用事务来保证一系列操作的原子性和一致性,这对于构建可靠的应用程序至关重要

1 什么是Redis事务🍀

​ Redis 事务的本质是一组命令的集合。事务支持一次执行多个命令,一个事务中所有命令都会被序列化。在事务执行过程,会按照顺序列化执行队列中的命令,其他客户端提交的命令请求不会插入到事务执行命令序列中

总结说:redis 事务就是一次性、顺序性、排他性的执行一个队列中的一系列命令

2 Redis事务相关命令和使用🍀

MULTI、EXEC、DISCARD 和 WATCH 是 Redis 事务相关的命令

  • MULTI :开启事务,redis会将后续的命令逐个放入队列中,然后使用EXEC命令来原子化执行这个命令系列

    原子化执行,它们要么全部执行成功,要么全部回滚。

  • EXEC:执行事务中的所有操作命令

  • DISCARD:取消事务,放弃执行事务块中的所有命令

  • WATCH:监视一个或多个key,如果事务在执行前,这个key(或多个key)被其他命令修改,则事务被中断,不会执行事务中的任何命令

  • UNWATCH:取消WATCH对所有key的监视

1.标准的事务执行

给k1、k2分别赋值,在事务中修改k1、k2,执行事务后,查看k1、k2值都被修改

127.0.0.1:6379[1]> set key1 value1
OK
127.0.0.1:6379[1]> set key2 value2
OK
127.0.0.1:6379[1]> multi # 开启事务
OK
127.0.0.1:6379[1](TX)> set key1 11
QUEUED
127.0.0.1:6379[1](TX)> set key2 22
QUEUED
127.0.0.1:6379[1](TX)> exec # 执行事务中所有的操作命令
1) OK
2) OK
127.0.0.1:6379[1]> get key1
"11"
127.0.0.1:6379[1]> get key2
"22"
2.事务取消
127.0.0.1:6379[1]> multi
OK
127.0.0.1:6379[1](TX)> set key1 111
QUEUED
127.0.0.1:6379[1](TX)> set key2 222
QUEUED
127.0.0.1:6379[1](TX)> DISCARD # 取消事务
OK
127.0.0.1:6379[1]> exec
(error) ERR EXEC without MULTI
3.事务出现错误的处理
  • 语法错误(编译器错误)

在开启事务后,修改k1值为11,k2值为22,但k2语法错误,最终导致事务提交失败,k1、k2保留原值

127.0.0.1:6379> set k1 v1
OK
127.0.0.1:6379> set k2 v2
OK
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> set k1 11
QUEUED
127.0.0.1:6379> sets k2 22
(error) ERR unknown command `sets`, with args beginning with: `k2`, `22`, 
127.0.0.1:6379> exec
(error) EXECABORT Transaction discarded because of previous errors.
127.0.0.1:6379> get k1
"v1"
127.0.0.1:6379> get k2
"v2"
127.0.0.1:6379>
  • Redis类型错误(运行时错误)

​ 在开启事务后,修改k1值为11,k2值为22,但将k2的类型作为List,在运行时检测类型错误,最终导致事务提交失败,此时事务并没有回滚,而是跳过错误命令继续执行, 结果k1值改变、k2保留原值

127.0.0.1:6379> set k1 v1
OK
127.0.0.1:6379> set k1 v2
OK
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> set k1 11
QUEUED
127.0.0.1:6379> lpush k2 22
QUEUED
127.0.0.1:6379> EXEC
1) OK
2) (error) WRONGTYPE Operation against a key holding the wrong kind of value
127.0.0.1:6379> get k1
"11"
127.0.0.1:6379> get k2
"v2"
127.0.0.1:6379>

3 CAS操作实现乐观锁🍀

WATCH 命令可以为 Redis 事务提供 check-and-set (CAS)行为

  • CAS? 乐观锁?Redis官方的例子帮你理解

被 WATCH 的键会被监视,并会发觉这些键是否被改动过了。如果有至少一个被监视的键在 EXEC 执行之前被修改了, 那么整个事务都会被取消, EXEC 返回nil-reply来表示事务已经失败。

举个例子, 假设我们需要原子性地为某个值进行增 1 操作(假设 INCR 不存在)。

首先我们可能会这样做:

val = GET mykey
val = val + 1
SET mykey $val

上面的这个实现在只有一个客户端的时候可以执行得很好。但是, 当多个客户端同时对同一个键进行这样的操作时, 就会产生竞争条件。举个例子, 如果客户端 A 和 B 都读取了键原来的值, 比如 10 , 那么两个客户端都会将键的值设为 11 , 但正确的结果应该是 12 才对。

有了 WATCH ,我们就可以轻松地解决这类问题了:

WATCH mykey
val = GET mykey
val = val + 1
MULTI
SET mykey $val
EXEC

使用上面的代码, 如果在 WATCH 执行之后, EXEC 执行之前, 有其他客户端修改了 mykey 的值, 那么当前客户端的事务就会失败。程序需要做的, 就是不断重试这个操作, 直到没有发生碰撞为止。

这种形式的锁被称作乐观锁, 它是一种非常强大的锁机制。并且因为大多数情况下, 不同的客户端会访问不同的键, 碰撞的情况一般都很少, 所以通常并不需要进行重试。

  • watch是如何监视实现的呢

Redis使用WATCH命令来决定事务是继续执行还是回滚,那就需要在MULTI之前使用WATCH来监控某些键值对,然后使用MULTI命令来开启事务,执行对数据结构操作的各种命令,此时这些命令入队列。

当使用EXEC执行事务时,首先会比对WATCH所监控的键值对,如果没发生改变,它会执行事务队列中的命令,提交事务;如果发生变化,将不会执行事务中的任何命令,同时事务回滚。当然无论是否回滚,Redis都会取消执行事务前的WATCH命令

  • watch 命令实现监视

在事务开始前用WATCH监控k1,之后修改k1为11,说明事务开始前k1值被改变,MULTI开始事务,修改k1值为12,k2为22,执行EXEC,发回nil,说明事务回滚;查看下k1、k2的值都没有被事务中的命令所改变。

127.0.0.1:6379> set k1 v1
OK
127.0.0.1:6379> set k2 v2
OK
127.0.0.1:6379> WATCH k1
OK
127.0.0.1:6379> set k1 11
OK
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> set k1 12
QUEUED
127.0.0.1:6379> set k2 22
QUEUED
127.0.0.1:6379> EXEC
(nil)
127.0.0.1:6379> get k1
"11"
127.0.0.1:6379> get k2
"v2"
  • UNWATCH取消监视
127.0.0.1:6379> set k1 v1
OK
127.0.0.1:6379> set k2 v2
OK
127.0.0.1:6379> WATCH k1
OK
127.0.0.1:6379> set k1 11
OK
127.0.0.1:6379> UNWATCH
OK
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> set k1 12
QUEUED
127.0.0.1:6379> set k2 22
QUEUED
127.0.0.1:6379> exec
1) OK
2) OK
127.0.0.1:6379> get k1
"12"
127.0.0.1:6379> get k2
"22"
127.0.0.1:6379>

4 Redis事务执行步骤🍀

通过上文命令执行,很显然Redis事务执行是三个阶段:

  • 开启:以MULTI开始一个事务
  • 入队:将多个命令入队到事务中,接到这些命令并不会立即执行,而是放到等待执行的事务队列里面
  • 执行:由EXEC命令触发事务

当一个客户端切换到事务状态之后, 服务器会根据这个客户端发来的不同命令执行不同的操作:

  • 如果客户端发送的命令为 EXEC 、 DISCARD 、 WATCH 、 MULTI 四个命令的其中一个, 那么服务器立即执行这个命令。
  • 与此相反, 如果客户端发送的命令是 EXEC 、 DISCARD 、 WATCH 、 MULTI 四个命令以外的其他命令, 那么服务器并不立即执行这个命令, 而是将这个命令放入一个事务队列里面, 然后向客户端返回 QUEUED 回复。

更深入的理解

我们再通过几个问题来深入理解Redis事务。

为什么 Redis 不支持回滚?

如果你有使用关系式数据库的经验,那么“Redis 在事务失败时不进行回滚,而是继续执行余下的命令”这种做法可能会让你觉得有点奇怪。

以下是这种做法的优点:

  • Redis 命令只会因为错误的语法而失败(并且这些问题不能在入队时发现),或是命令用在了错误类型的键上面:这也就是说,从实用性的角度来说,失败的命令是由编程错误造成的,而这些错误应该在开发的过程中被发现,而不应该出现在生产环境中。
  • 因为不需要对回滚进行支持,所以 Redis 的内部可以保持简单且快速。

有种观点认为 Redis 处理事务的做法会产生 bug , 然而需要注意的是, 在通常情况下, 回滚并不能解决编程错误带来的问题。举个例子, 如果你本来想通过 INCR 命令将键的值加上 1 , 却不小心加上了 2 , 又或者对错误类型的键执行了 INCR , 回滚是没有办法处理这些情况的。

如何理解Redis与事务的ACID?

一般来说,事务有四个性质称为ACID,分别是原子性,一致性,隔离性和持久性

  • 原子性atomicity

    # 首先通过上文知道 运行期的错误是不会回滚的,很多文章由此说Redis事务违背原子性的;而官方文档认为是遵从原子性的。Redis官方文档给的理解是,**Redis的事务是原子性的:所有的命令,要么全部执行,要么全部不执行**。而不是完全成功
    
  • 一致性consistency

    #  redis事务可以保证命令失败的情况下得以回滚,数据能恢复到没有执行之前的样子,是保证一致性的,除非redis进程意外终结
    
  • 隔离性Isolation

    #  redis事务是严格遵守隔离性的,原因是redis是单进程单线程模式(v6.0之前),可以保证命令执行过程中不会被其他客户端命令打断.但是,Redis不像其它结构化数据库有隔离级别这种设计
    
  • 持久性Durability

    #  **redis事务是不保证持久性的**,这是因为redis持久化策略中不管是RDB还是AOF都是异步执行的,不保证持久性是出于对性能的考虑
    

5 Redis事务其它实现🍀

  • 基于Lua脚本,Redis可以保证脚本内的命令一次性、按顺序地执行,其同时也不提供事务运行错误的回滚,执行过程中如果部分命令运行错误,剩下的命令还是会继续运行完
  • 基于中间标记变量,通过另外的标记变量来标识事务是否执行完成,读取数据时先读取该标记变量判断是否事务执行完成。但这样会需要额外写代码实现,比较繁琐

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

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

相关文章

高效学习工作SMART原则

S代表Specific(明确具体的),意味着你需要清晰地定义你的目标,并确保它是具体而明确的。例如,如果你的目标是“提高销售”,那么这个目标就不是足够具体。更好的表述可能是:“在接下来的三个月内&…

【Python报错已解决】 ModuleNotFoundError: No module named ‘lime‘

🎬 鸽芷咕:个人主页 🔥 个人专栏: 《C干货基地》《粉丝福利》 ⛺️生活的理想,就是为了理想的生活! 专栏介绍 在软件开发和日常使用中,BUG是不可避免的。本专栏致力于为广大开发者和技术爱好者提供一个关于BUG解决的经…

828华为云征文 | 利用FIO工具测试Flexus云服务器X实例存储性能

目录 一、Flexus云服务器X实例概要 1.1 Flexus云服务器X实例摘要 1.2 产品特点 1.3 存储方面性能 1.4 测评服务器规格 二、FIO工具 2.1 安装部署FIO 2.2 主要性能指标概要 三、进行压测 3.1 测试全盘随机读IO延迟 3.2 测试全盘随机写IO延迟 3.3 测试随机读IOPS 3.4…

《后端程序猿 · Spring事务失效场景》

📢 大家好,我是 【战神刘玉栋】,有10多年的研发经验,致力于前后端技术栈的知识沉淀和传播。 💗 🌻 CSDN入驻不久,希望大家多多支持,后续会继续提升文章质量,绝不滥竽充数…

如何使用ssm实现钢铁集团公司安全管理系统的构建与实现

TOC ssm748钢铁集团公司安全管理系统的构建与实现jsp 研究背景与现状 时代的进步使人们的生活实现了部分自动化,由最初的全手动办公已转向手动自动相结合的方式。比如各种办公系统、智能电子电器的出现,都为人们生活的享受提供帮助。采用新型的自动化…

SpringBoot教程(三十一) | SpringBoot生成Docker镜像包

SpringBoot教程(三十) | SpringBoot生成Docker镜像包 前提方式一:spring-boot-maven-plugin 方式方式二:Dockfile 方式(推荐) 前提 如果你在 Windows 上,确保 Docker Desktop 已经启动并正在运…

Java常用三类定时器快速入手指南

文章目录 Java常用三类定时器快速入手指南一、序言二,Timer相关1、概念2、Timer类3、TimerTask类4、ScheduleExecutorService接口 三,Scheduled相关1、配置1.1 SpringMVC配置1.2 SpringBoot配置(1)单线程(2&#xff09…

python 如何引用变量

在字符串中引入变量有三种方法: 1、 连字符 name zhangsan print(my name is name) 结果为 my name is zhangsan 2、% 字符 name zhangsan age 25 price 4500.225 print(my name is %s%(name)) print(i am %d%(age) years old) print(my price is %f%(pric…

【数字图像处理】小白也能懂,最浅显方式手撕直方图均衡化(附python实现)

文章目录 1 概念2 原理2.1 数学原理 3 python代码实现4 测试效果5 结论 1 概念 直方图均衡化,同伽马变换一样,也是增强图像对比度的一种工具。区别在于,直方图均衡化是一种自适应的工具,即自动工具。也就是说,我们只需…

使用RestTemplate调用EMQX API查询MQTT客户端列表信息

项目中集成mqtt客户端查询功能,使用到了EMQX api-v5,具体步骤: 一、准备工作 首先在EMQX dashboard中添加API 密钥 填写密钥名称,点击确定,会生成API Key和Secret Key,保存起来备用。 二、配置文件 在…

SUP-NeRF-ECCV2024数据集: 单目3D对象重建的新突破

2024-09-25,由Bosch Research North America和Michigan State University联合发布的SUP-NeRF,是一个基于单目图像进行3D对象重建的新型方法。一个无缝集成姿态估计和物体重建的统一网格。 ECCV:欧洲计算机视觉会议的缩写,它是计算…

如何使用ssm实现科技银行业务管理系统+vue

TOC ssm743科技银行业务管理系统vue 第一章 绪论 1.1 研究背景 在现在社会,对于信息处理方面,是有很高的要求的,因为信息的产生是无时无刻的,并且信息产生的数量是呈几何形式的增加,而增加的信息如何存储以及短时间…

移除元素

移除元素 题目链接:移除元素 示例 1: 输入:nums [3,2,2,3], val 3 输出:2, nums [2,2,_,_] 解释:你的函数函数应该返回 k 2, 并且 nums 中的前两个元素均为 2。 你在返回的 k 个元素之外留下了什么并不重要&…

URL从输入到⻚面显示的过程(详细版)

URL从输入到⻚面显示的过程(详细版) 浏览器中输入网址 DNS 解析域名得到 IP 地址 DNS 解析首先会从你的浏览器的缓存中去寻找是否有这个网址对应的 IP 地址,如果没有就向OS系统的 DNS 缓存中寻找,如果没有就是路由器的 DNS 缓存&…

C++之 友元重载 以及最常用的几种友元函数

在之前的友元中就曾经讲过,我们为了去访问修改私有成员中的数据时,只能通过公有的办法去进行访问操作,非常的局限。所以C引用了友元函数,只要加上friend关键字,C的这个类,会自动把这个函数的权限拉到类内&a…

无水印短视频素材下载网站有哪些?十个高清无水印视频素材网站分享

你知道怎么下载无水印视频素材吗?今天小编就给大家推荐十个高清无水印视频素材下载的网站,如果你也是苦于下载高清无水印的短视频素材,赶紧来看看吧~ 1. 稻虎网 首推的是稻虎网。这个网站简直就是短视频创作者的宝库。无论你需要…

编程魔法:基于LLM的AI function开发,如何实现高效数据生成?

基于大语言模型(LLM)的AI function开发,简直就是现代编程界的“魔法棒”! 你好,我是三桥君 最近三桥君有个任务,需要造一些测试数据,比如姓名、手机号、银行卡号、邮箱啥的,用来做测…

每日OJ题_牛客_添加逗号_模拟_C++_Java

目录 牛客_添加逗号_模拟 题目解析 C代码1 C代码2 Java代码 牛客_添加逗号_模拟 添加逗号_牛客题霸_牛客网 题目解析 读取输入:读取一行字符串。分割字符串:使用空格将字符串分割成单词数组。拼接字符串:将单词数组中的每个单词用逗号…

群晖安装Gitea(代码托管工具)

一、Gitea介绍 Gitea 是一款开源的轻量级代码托管平台,可以为团队和开发者提供了一个易于部署、运行快速、使用体验良好的自建 Git 服务。相比于其它自部署代码托管平台,Gitea 的设计更加轻量,对系统资源的占用相对较少,能够在较低配置的服务器上流畅运行。相比于其他代码…

嘉楠科技AI芯片K230-初探

勘智K230 介绍入门购买开发板 安装开机开发学习点亮第1个LED点亮屏幕预览摄像头代码离线运行 在线训练平台 参考 介绍 K230芯片是嘉楠科技 Kendryte系列AIoT芯片中的最新一代SoC产品。该芯片采用全新的多异构单元加速计算架构,集成了2个RISC-V高能效计算核心&#x…