Redis 7.x 系列【18】事务

news2025/1/19 14:35:22

有道无术,术尚可求,有术无道,止于术。

本系列Redis 版本 7.2.5

源码地址:https://gitee.com/pearl-organization/study-redis-demo

文章目录

    • 1. 概述
    • 2. 命令
      • 2.1 MULTI
      • 2.2 EXEC
      • 2.3 DISCARD
      • 2.4 WATCH
      • 2.5 UNWATCH
    • 3. 事务中的错误
    • 4. 和数据库事务的区别
      • 4.1 原子性
      • 4.2 隔离性
      • 4.3 持久性
      • 4.4 一致性
    • 5. 脚本和事务

1. 概述

官方文档

Redis 事务:允许在单个步骤中执行一组命令,其核心命令包括 MULTIEXECDISCARDWATCH

Redis 事务提供了两个重要的保证:

  • 所有事务中的命令都是串行化执行的,按顺序逐一执行。在事务执行过程中,不会在命令执行的中间阶段响应其他客户端的请求,这确保了命令作为单个隔离操作执行。
  • EXEC 命令触发事务中所有命令的执行:
    • 如果客户端在调用 EXEC 命令之前在事务上下文中失去了与服务器的连接,那么所有操作都不会执行。
    • 一旦调用 EXEC 命令,所有操作将被执行。
    • 在使用AOF时,确保使用单个系统调用将事务写入磁盘。如果Redis服务器崩溃或被系统管理员强制终止,可能会导致仅部分操作被记录。会在重新启动时检测到此条件,并报错退出。通过使用 redis-check-aof 工具,可以修复追加写入文件,删除部分事务,以便服务器能够重新启动。

自版本 2.2 起,Redis在上述两个保证之外提供了额外的保证,采用了乐观锁的方式,与检查和设置(CAS)操作非常类似。

注意Redis 不支持事务的回滚操作,因为支持回滚会对 Redis 的简单性和性能产生影响。

2. 命令

MULTIEXECDISCARDWATCHRedis 事务相关的命令。

2.1 MULTI

MULTI 命令用于开启一个事务,它总是返回 OK MULTI 执行之后, 客户端可以继续向服务器发送任意多条命令, 这些命令不会立即被执行, 而是被放到一个队列中, 当 EXEC命令被调用时, 所有队列中的命令才会被执行。

当客户端处于事务状态时, 所有传入的命令都会返回一个内容为 QUEUED 的状态回复, 这些被入队的命令将在 EXEC 命令被调用时执行。

示例:

127.0.0.1:6379> MULTI
OK
127.0.0.1:6379(TX)> set k1 v1 
QUEUED
127.0.0.1:6379(TX)> set k2 v2
QUEUED

2.2 EXEC

EXEC 命令用于执行事务队列内的所有命令,返回值为事务块内所有命令的返回值,按命令执行的先后顺序排列。当操作被打断时,返回空值 nil

示例:

127.0.0.1:6379(TX)> exec 
1) OK
2) OK

2.3 DISCARD

DISCARD 命令用于取消事务,放弃执行事务队列内的所有命令,恢复连接为非事务模式。

示例:

127.0.0.1:6379> multi
OK
127.0.0.1:6379(TX)> set k2 v2
QUEUED
127.0.0.1:6379(TX)> discard 
OK

2.4 WATCH

WATCH 命令用于监视一个或多个 key ,当被 WATCHkey 被修改时,事务才会被执行。如果在事务执行期间这些键被其他客户端修改,那么该事务执行会被打断。

基本语法:

WATCH key [key ...]

示例,客户端监视 k1
在这里插入图片描述
打开另外一个客户端,对 k1 进行修改操作:
在这里插入图片描述
之前的客户端执行事务操作时,EXEC 返回 nil
在这里插入图片描述

注意事项:

  • Redis 6.0.9之前的版本中,过期的键不会导致事务中止。
  • WATCH 命令仅在事务中使用才有意义,因为它是为了配合事务而设计的乐观锁机制。
  • WATCH 可以被调用多次,从调用开始,直到EXEC调用结束。
  • 被监视的 key 在事务执行之前,会被Redis服务器记录下来,并在执行 EXEC 命令时检查这些键是否被修改。
  • 如果在 WATCHEXEC 之间发生了其他客户端的写操作,事务将会失败。此时,客户端可以根据返回值 nil 来判断事务执行是否成功。
  • 一旦执行 EXEC 或者关闭客户端连接,所有的 WATCH 都会被取消。
  • WATCH 命令在处理并发操作时非常有用,它可以帮助保证事务的原子性和一致性,是实现复杂事务逻辑的重要组成部分。

使用场景:

  • 实现乐观锁:WATCH 命令允许在事务执行前检查键是否被其他客户端修改,从而避免并发冲突,是实现乐观锁的重要手段之一。
  • 事务中的条件控制:当事务需要根据某些条件来执行或取消执行时,可以使用 WATCH 来检查条件是否满足。

2.5 UNWATCH

UNWATCH 命令用于取消 WATCH 命令对所有 key 的监视。如果执行过 EXECDISCARD,会自动取消监视,无需再执行 UNWATCH

示例:

localhost:0>UNWATCH
"OK"

3. 事务中的错误

Redis 事务中,可能会遇到两种类型的命令错误:

  • 在调用EXEC之前,某些命令可能会失败无法入队。例如,命令可能存在语法错误,或者可能出现关键条件,例如内存不足等。
  • 在调用EXEC之后,某些命令可能会失败。例如,可能对一个键执行了与其值类型不符的操作,例如对字符串值执行列表操作等。

Redis 2.6.5 开始,服务器会在累积命令期间检测到错误。如果发现错误,它将拒绝执行事务并在EXEC期间返回错误,丢弃该事务。而在EXEC之后发生的错误不会以特殊方式处理,即使事务中的某些命令失败,其他所有命令仍将被执行。

示例,在调用EXEC之前的命令存在语法错误时,不会被添加到队列:

localhost:0>MULTI
"OK"
localhost:0>INCR a b c
"ERR wrong number of arguments for 'incr' command"

示例,命令的语法都是正确的,在调用EXEC之后,由于 LPOP 操作的对象是一个字符串,所以这个命令执行失败,但是队列中的其他命令仍会被执行:

localhost:0>MULTI
"OK"
localhost:0>SET a abc
"QUEUED"
localhost:0>LPOP a
"QUEUED"
localhost:0>SET b efg
"QUEUED"
localhost:0>EXEC
 1)  "OK"
 2)  "WRONGTYPE Operation against a key holding the wrong kind of value"
 3)  "OK"

4. 和数据库事务的区别

关系型数据库事务:事务保证一系列操作要么全部成功,要么全部失败,如果某一步出现了异常,数据就会回滚,把之前的操作撤销。数据库事务需要满足四大特性(简称ACID),即原子性隔离性持久性一致性,才能保证数据正确性。

4.1 原子性

关系型数据库事务具有严格的原子性,要么所有操作都执行成功并永久保存(提交),要么所有操作都不执行(回滚)。

Redis 事务允许一组命令作为一个原子操作进行执行。但是,不是严格的原子性,如果在执行期间发生错误,部分命令可能已经执行,而另一部分可能未执行。

4.2 隔离性

关系型数据库事务通过锁和多版本并发控制(MVCC)等机制来实现不同事务之间的隔离性,例如读未提交、读已提交、可重复读和串行化等级别。

Redis事务提供了一定的隔离性,但没有像传统数据库那样严格的隔离级别。不同客户端的事务可能会相互干扰,需要通过WATCH命令显式地实现乐观锁机制。

4.3 持久性

关系型数据库事务中,事务提交后,数据会被持久化到磁盘,保证数据不会丢失。

Redis 通过持久化机制来实现持久性,但在事务提交时并没有严格保证数据已经永久保存。

4.4 一致性

关系型数据库事务中,发生错误时,数据库可以进行回滚操作,保证事务执行前后数据的一致性。

Redis事务中的某个命令执行失败,后续的命令仍然会继续执行,不会回滚已经执行的命令,无法保证一致性。

5. 脚本和事务

从定义上来说, Redis 中的脚本本身就是一种事务, 所以任何在事务里可以完成的事, 在脚本里面也能完成。 并且一般来说, 使用脚本要来得更简单,并且速度更快。

因为脚本功能是 Redis 2.6 才引入的, 而事务功能则更早之前就存在了, 所以 Redis 才会同时存在两种处理事务的方法。

不过官方并不打算在短时间内就移除事务功能, 因为事务提供了一种即使不使用脚本, 也可以避免竞争条件的方法, 而且事务本身的实现并不复杂。

不过在不远的将来, 可能所有用户都会只使用脚本来实现事务也说不定。 如果真的发生这种情况的话, 那么将废弃并最终移除事务功能。

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

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

相关文章

动态校验列表数据方案

背景:当select 选择A 的时候是必填,选B的时候是非必填 那么我们需要监听 selec 变化时候对 列表的 :edit-rules“validRulesList” 进行重新赋值必填校验的true, (跟对列表内上传文件,对列表文件进行赋值名字一样道理,…

在Linux上查找文件的2个好用的命令

1. locate xx (查找带xx字符的所有文件或目录) 在终端输入命令 locate lua,可以看到,所有带lua字符的文件或目录都会被搜索出来。 2. find / -name xx (查找名为xx的文件或目录) 在终端输入命令 find …

Java通过GeoLite2-City.mmdb 进行IP信息查询地理定位和经纬度筛选。

引入依赖 <dependency><groupId>com.maxmind.geoip2</groupId><artifactId>geoip2</artifactId><version>4.2.0</version> </dependency>下载数据文件&#xff1a;https://download.lin2ur.cn/GeoLite2/ package com.cqclo…

Springboot+Vue3开发学习笔记《2》

SpringbootVue3开发学习笔记《2》 博主正在学习SpringbootVue3开发&#xff0c;希望记录自己学习过程同时与广大网友共同学习讨论。 总共涉及两部分&#xff0c;第一部分为基础部分学习&#xff0c;第二部分为实战部分。 一、学习路径 1.1 基础部分 配置文件整合MyBatisBea…

#### golang中【堆】的使用及底层 ####

声明&#xff0c;本文部分内容摘自&#xff1a; Go: 深入理解堆实现及应用-腾讯云开发者社区-腾讯云 数组实现堆 | WXue 堆&#xff08;Heap&#xff09;是实现优先队列的数据结构&#xff0c;Go提供了接口和方法来操作堆。 应用 package mainimport ("container/heap&q…

深度解析Java世界中的对象镜像:浅拷贝与深拷贝的奥秘与应用

在Java编程的浩瀚宇宙中&#xff0c;对象拷贝是一项既基础又至关重要的技术。它直接关系到程序的性能、资源管理及数据安全性。然而&#xff0c;提及对象拷贝&#xff0c;不得不深入探讨其两大核心类型&#xff1a;浅拷贝&#xff08;Shallow Copy&#xff09;与深拷贝&#xf…

2024最全软件测试面试八股文(答案+文档+视频讲解)

Part1 1、你的测试职业发展是什么&#xff1f; 测试经验越多&#xff0c;测试能力越高。所以我的职业发展是需要时间积累的&#xff0c;一步步向着高级测试工程师奔去。而且我也有初步的职业规划&#xff0c;前3年积累测试经验&#xff0c;按如何做好测试工程师的要点去要求自…

动态规划入门,从简单递归到记忆化搜索到动态规划

动态规划入门&#xff0c;从简单递归到记忆化搜索到动态规划 打家劫舍 class Solution {private int nums[];public int rob(int[] nums) {this.nums nums;return dfs(nums.length - 1);}public int dfs(int i){if (i < 0){return 0;}int res Math.max(dfs(i - 1), dfs(i…

Python学习篇:Python基础知识(三)

目录 1 Python保留字 2 注释 3 行与缩进 ​编辑4 多行语句 5 输入和输出 6 变量 7 数据类型 8 类型转换 9 表达式 10 运算符 1 Python保留字 Python保留字&#xff08;也称为关键字&#xff09;是Python编程语言中预定义的、具有特殊含义的标识符。这些保留字不能用作…

【UML用户指南】-28-对体系结构建模-部署

目录 1、名称 2、节点与制品 2.1、结点与制品相同&#xff1a; 2.2、不同 3、组织结点 4、连接 5、常用建模技术 5.1、对处理器和设备建模 5.2、对制品的分布建模 正如制品一样&#xff0c;结点存在于物质世界中&#xff0c;在对系统的物理方面建模中它是一个重要构造…

Python——面向对象编程(类和对象)2

目录 私有属性和私有方法 01.应用场景及定义方式 02.伪私有属性和私有方法 继承 1.1继承的概念、语法和特点 1.继承的语法&#xff1a; 2.专业术语&#xff1a; 3.继承的传递性 1.2方法的重写 1.覆盖父类的方法 2.对父类方法进行扩展 关于super 1.3 父类的私有属性和…

数据看板/可视化大屏的实际价值到底是什么?详解数据可视化的实用之处

数据驾驶舱/数据看板/可视化大屏的实际价值&#xff0c;取决于使用者的实际需求。 华而不实&#xff1f;华就是实&#xff01; 关于可视化大屏最广泛的争议&#xff0c;便是对其“华而不实”的批评&#xff0c;认为可视化大屏缺乏技术含量&#xff0c;只是一钟比较高级的“装饰…

WRF学习——使用CMIP6数据驱动WRF/基于ncl与vdo的CMIP6数据处理

动力降尺度 国际耦合模式比较计划&#xff08;CMIP&#xff09;为研究不同情景下的气候变化提供了大量的模拟数据&#xff0c;而在实际研究中&#xff0c;全球气候模式输出的数据空间分辨率往往较低&#xff08;>100Km&#xff0c;缺乏区域气候特征&#xff0c;为了更好地研…

析构函数和拷贝构造函数

文章目录 析构函数1.析构函数的定义&#xff1a;2.析构函数的语法&#xff1a;3.析构函数的特性&#xff1a; 拷贝构造函数1.拷贝构造函数的定义&#xff1a;2.拷贝构造函数的语法3.拷贝构造函数的特性(1)拷贝构造函数是构造函数的一个重载形式**(这个其实也很好理解&#xff0…

鸿蒙小案例-首选项工具类

一个简单的首选项工具类 主要提供方法 初始化 init()方法建议在EntryAbility-》onWindowStageCreate 方法中使用 没多少东西&#xff0c;放一下测试代码 import { PrefUtil } from ./PrefUtil; import { promptAction } from kit.ArkUI;Entry Component struct PrefIndex {St…

关于软件本地化,您应该了解什么?

软件本地化是调整软件应用程序以满足目标市场的语言、文化和技术要求的过程。它不仅仅涉及翻译用户界面&#xff1b;它包含一系列活动&#xff0c;以确保软件在目标语言环境中可用且相关。以下是您应该了解的有关软件本地化的一些关键方面&#xff1a; 了解范围 软件本地化是…

学生用小台灯什么牌子的好?列举出几款学生用台灯推荐

眼睛是我们感知世界的窗口&#xff0c;但近年来&#xff0c;儿童青少年的视力健康却受到了严重困扰。数据显示&#xff0c;近视问题在儿童群体中呈现出明显的增长趋势&#xff0c;这给他们的学习和生活带来了诸多不便。虽然现代科技的快速发展使得电子产品成为了我们生活中不可…

UE5.4新功能 - Texture Graph上手简介

TextureGraph是UE5.4还在实验(Experimental)阶段的新功能&#xff0c;该功能旨在材质生成方面达到类似Subtance Designer的效果&#xff0c;从而程序化的生成一些纹理。 本文就来简要学习一下。 1.使用UE5.4或以上版本&#xff0c;激活TextureGraph插件 2.内容视图中右键找到…

React@16.x(47)路由v5.x(12)源码(4)- 实现 Route

目录 1&#xff0c;原生 Route 的渲染内容2&#xff0c;实现 1&#xff0c;原生 Route 的渲染内容 对如下代码来说&#xff1a; import { BrowserRouter as Router, Route } from "react-router-dom"; function News() {return <div>News</div>; }func…

【前端】IntersectionObserver 实现图片懒加载和无限滚动

【前端】IntersectionObserver 实现图片懒加载和无限滚动 在前端开发中&#xff0c;性能优化是一个重要的考量因素。随着现代网页和应用的复杂性增加&#xff0c;确保页面快速加载和流畅运行变得越来越重要。本文将介绍一种强大的工具——IntersectionObserver API&#xff0c…