Redis 事务 总结

前言


 相关系列

  • 《Redis & 目录》(持续更新)
  • 《Redis & 事务 & 源码》(学习过程/多有漏误/仅作参考/不再更新)
  • 《Redis & 事务 & 总结》(学习总结/最新最准/持续更新)
  • 《Redis & 事务 & 问题》(学习解答/持续更新)
     

 参考文献

  • 《Redis事务详解》
     
     

概述


    Redis事务并不严格具备ACID属性。在我们对数据库的常规理解中,事务必然会严格遵守原子性/一致性/隔离性/持久性。但由于Redis基于内存设计/实现的原因,其对事务ACID属性的实现并不存在/彻底。因此与其称之为事务,将之称为批处理其实更加贴切…该知识点会在下文讲解ACID时详述。

    Redis事务的意义是为了防止插队。Redis事务中的指令会被打包一次执行,因此可以避免多客户端指令交互执行的情况发生。
 
 

使用


 开启/执行/取消

    事务的开启/执行/取消指令具体如下:

  • MULTI:开启事务;
  • EXEC:执行事务;
// ---- 设置一个键/值为num/1的键值对。
> SET num 1
OK
// ---- 开启事务,并依次递增/递减/递增。每个指令输入后都会返回QUEUED,意味着指令已被成功加入
// 事务队列中,等待最终被执行。
> MULTI
OK
> INCR num
QUEUED
> DECR num
QUEUED
> INCR num
QUEUED
// ---- 执行事务,并返回每条指令的执行结果。
> EXEC
2
1
2
  • DISCARD:在执行前取消事务。
> SET num 1
OK
// ---- 开启事务,并添加递增/递减/递增指令。
> MULTI
OK
> INCR num
QUEUED
> DECR num
QUEUED
> INCR num
QUEUED
// ---- 取消事务。
> DISCARD
OK
// ---- 取消事务后再执行会抛出错误。
> EXEC
(error) ERR EXEC without MULTI

 

 阶段

    Redis事务分为组队/执行两个阶段。组队阶段是Redis事务的第一阶段,由指令“MULTI”在开启事务时同步开启。在组队阶段中Redis会创建相应的事务队列用于顺序接收客户端发送的各项指令,因此事务中的指令其实是多次发送的。而由于Redis不可能在客户端发送全部指令/发送“EXEC”指令/发送“DISCARD”前无限等待,因为整个事务指令发送过程的时长并不可控,因此Redis实际上可以并发接受多个客户端指令。这种并发接收可能是单线程在多客户端之间相互切换实现的,也可能真的有多个线程在各自为政,这具体与Redis的版本有关。随着Redis的不断发展,早期(6.0之前)版本的“单线程实现”描述其实已经不太准确了,就比如现今绝大多数版本的Redis都会启用额外线程来实现数据持久化。但一直以来始终不变的是指令必然只会由唯一的主线程执行,因此在该设计被破坏前,无论Redis如何引入多线程,其都可以被称为单线程实现。

在这里插入图片描述

    Redis事务可能无法进入执行阶段。执行阶段顾名思义,即是将已完成组队的事务指令整体交由主线程依次执行。而由于执行阶段会由“EXEC”负责开启,因此如果客户端事先发送了“DISCARD”指令,那么事务/事务队列就会直接结束/丢弃而无法进入执行阶段。而除此之外如果客户端发送的指令出现语法错误,那事务也会因为原子性而直接结束…该知识点会在下文讲解原子性时详述。
 
 

实现


 原子性

    Redis事务具备“伪”原子性。原子性通俗的说法就是“要么一起成功,要么一起失败”,关于Redis事务的原子性一直是相当具有争议的点,原因就是其未曾“完全”遵循原子性的定义,即其允许在某些情况下部分成功。因此Redis具备原子性虽然属于官方说法,但仍有部分开发者坚持认为其并不具备原子性。而对于作者本人而言我认为Redis是具有原子性的,只是基于其功能定位而难以/无法实现的足够彻底而已,因此我将这种原子性称为“伪”原子性。

    Redis事务在组队阶段具备“真”原子性。对于在组队阶段的事务而言,如果客户端输入的指令在语法上存在错误,那么其整个事务/事务队列都会直接结束/丢弃。该行为符合原子性的标准定义,因此Redis事务在组队阶段具备“真”原子性…具体图示/案例如下:

在这里插入图片描述

> SET num 1
OK
> MULTI
OK
> INCR num
QUEUED
// ---- 错误指令,不同版本的Redis/图形客户端在此会有不同的表现,我这里显示排队成功,但有些版本会直接报错。
> INCR1 num
QUEUED
> INCR num
QUEUED
// ---- 执行时由于存在错误指令会抛出异常,整体不执行。
> EXEC
ReplyError: EXECABORT Transaction discarded because of previous errors.

    Redis事务在执行阶段具备“伪”原子性。对于在执行阶段的事务而言,即使其在过程中出现某指令执行异常的情况,Redis也只会记录该异常并继续执行后续指令,因此Redis事务并不具备数据回滚能力。该行为明显违背了原子性的标准定义,因此Redis事务在执行阶段只具备“伪”原子性…具体图示/案例如下:

在这里插入图片描述

> SET name aaa
OK
> MULTI
OK
> SET name bbb
QUEUED
// ---- 该指令没有语法错误,但字符串类型是无法递增的。
> INCR name
QUEUED
> SET name ccc
QUEUED
// ---- 执行后只有两个结果,因为第二条指令会执行失败。可能是因为Redis版本/图形客户端
// 的原因,我这里没有抛出异常。
> EXEC
OK
OK

 

 一致性/持久性

    Redis事务具备结构一致性,但不具备内容一致性。Redis并不像Mysql一样对数据存在为空/大小/长度/范围/唯一/外键等结构性约束,故而事务数据只要计算成功其结构就必然合理,因此Redis事务具备结构一致性。但与此同时Redis事务却不具备内容一致性,因为其“伪”原子性无法保证所有指令全都执行成功。例如Redis事务就无法保证账号A/B在收/支上的一致性,因为两者的指令都存在失败可能,而任意一方的失败都将导致收支上的不平衡,因为Redis事务不具备内容一致性。

    Redis事务不(直接)具备持久性。所谓持久性是指数据被永久保存的特性,Redis存在RDB/AOF两种持久化机制,在两者被打开至少一个的情况下,Redis可以将内存中的数据持久化至磁盘中永久保存,从而“尽可能”避免在宕机/关机/重启/断电时丢失数据。该知识点会在Redis持久化的专项文章中详述,此处我们只需知道的是:虽然Redis具备全局性的数据持久化能力,但遗憾的是该机制的运行与事务是完全独立的,即事务的执行并不会强制触发该机制以实现对事务数据的持久化。因此Redis事务是不具备持久性的,虽然全局性的持久化机制可以在一定程度上间接达成这个效果。
 

 隔离性/WATCH

    Redis事务具备“读已递交”级别的隔离性。所谓隔离性是指事务并发期间的相互影响程度,这种相互影响在数据库的标准定义中被从低到高的被分为四个级别,其具体名称/问题/效果如下所示。而Redis没有设计任何专项机制去提升事务的隔离性,因此Redis事务仅天然具有“读已递交”级别的隔离性。为什么不是“读未递交”级别的隔离性呢?这是因为Redis事务压根没有统一递交的说法…其指令的每次执行都可以直接视作数据的一次递交。

名称问题效果
读未递交脏读/不可重复度/幻读会读取到其它事务未递交的数据,并且即无法保证数据的内容不变化,也无法保证数据的数量不变化
读已递交不可重复度/幻读不会读取到其它事务未递交的数据,但即无法保证数据的内容不变化,也无法保证数据的数量不变化
可重复读幻读不会读取到其它事务未递交的数据,并且可以保证数据的内容不变化,但无法保证数据的数量不变化
序列化/事务串行执行,相互之间完全不影响

    Redis事务在执行阶段具备“序列化”等级的隔离级别。由于单线程实现的原因,Redis事务在执行阶段其实具备“序列化”等级的隔离级别。因为在此期间其它事务最多只能处于组队阶段而无法处于执行阶段,甚至在早期版本中都可能不存在其它事务,因此对于当前正在执行的事务来说是绝对不可能出现目标数据被并发修改的情况的。那为什么说Redis事务只具备“读已递交”级别的隔离性呢?这是因为如果反过来看正处于组队阶段的当前事务,那么其目标数据就完全可能被处于执行阶段的其它事务所并发修改,从而导致出现执行前提被破坏的“竞态条件”情况…具体示例时间表如下:

时间事务1事务2
T1商品总量为5000,开启事务商品总量为5000,开启事务
T2组队指令 – 设置商品总量为4000(-1000)组队指令 – 设置商品总量为3000(-2000)
T3单线程执行指令 – 商品总量被设置为3000T4单线程执行指令 – 商品总量被设置为4000但正确总量应该为2000

    Redis提供了乐观锁机制的{WTACH}指令用于监控事务的目标数据。上述问题的本质还是线程安全问题,其核心在于指令的执行依据被并发修改,因此只要能够控制这一点就能为事务的正确执行提供基础可能。对此Redis基于乐观锁机制提供了{WTACH}指令用于监控目标数据,其本质是记录目标数据的快照。而当事务进入执行阶段时其会将最新的目标数据与快照进行对比,并在发现目标数据已变化的情况下拒绝执行事务并返回null…具体示例如下:

  • WATCH key [key …]:监控目标数据集,并在目标数据发生变化时拒绝执行事务。
        ------------------------- 入参 -------------------------
        key [key …] @ 键集:需监控目标数据集的键集,多个键之间使用" "分割。
// ---- 设置/监控目标数据,并开启事务。
> SET goal aaaa
OK
> WATCH goal
OK
> MULTI
OK
// ---- 更新目标数据。
> SET goal bbbb
QUEUED
// ---- 如果目标数据在事务组队期间被其它线程/事务修改,当前事务将不会执行并返回null。
> EXEC
null

 
 

管道


    管道可大幅提升多指令的执行效率。管道相当于将事务的组队阶段从服务端转移到了客户端执行,因此其不会像事务一样多次发送指令,而是会直接将已完成打包/组队的命令集一次性发送至服务端执行。而又因为Redis执行的高效性会使得指令/数据的RRT @ Round Trip Time @ 往返时间/网络传输时间远远多于指令的执行时间,因此多指令/数据的一次性发送/返回能够有效提升批量操作的执行效率,也因此管道被广泛用于数据大批量导入/导出的场景中。

在这里插入图片描述

    Redis管道无法通过原生指令开启…下文展示的是通过Jedis使用管道的模板:

public static void testPipeLineAndNormal(Jedis jedis) throws InterruptedException {// ---- 开启管道。Pipeline pipeline = jedis.pipelined();// ---- 在管道中添加多个SET指令。for (int i = 0; i < 10000; i++) {pipe.set(String.valueOf(i), String.valueOf(i));}// ---- 一次性发送/执行管道指令。pipe.sync();
}

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

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

相关文章

自旋锁原理及基于原子引用手写自旋锁

什么是自旋锁 自旋锁&#xff08;Spinlock&#xff09;是一种用于多线程同步的机制&#xff0c;在尝试获取锁时&#xff0c;如果锁已经被其他线程持有&#xff0c;则当前线程不会立即被阻塞&#xff0c;而是会进入一个循环中反复尝试获取锁&#xff0c;直到成功为止。这种机制通…

探索CRM功能:六个解决方案助力企业发展

在当前竞争激烈的市场环境中&#xff0c;企业面临着客户关系管理的诸多挑战&#xff0c;CRM&#xff08;客户关系管理&#xff09;系统能够有效解决客户数据孤岛、提升客户互动效率、增强销售预测准确性等问题。通过整合客户信息和优化业务流程&#xff0c;CRM帮助企业实现更高…

解决JeecgBoot微服务通过Gateway访问Swagger资源出现“Knife4j文档请求异常”

1.问题描述 基于jeecgboot单体版本,参照官方推荐的纯微服务项目拆分指南,对jeecgboot项目进行微服务拆分,将gateway和system模块启动成功后,通过gateway访问访问Swagger接口文档,出现“Knife4j文档请求异常”,如下图: 2.问题定位: 1.浏览器F12打开控制台,查看异常请…

Kafka-Eagle(可视化监控平台)安装教程

Kafka Eagle 1. Install Mysql Kafka-Eagle 的安装依赖于 MySQL&#xff0c;MySQL 主要用来存储可视化展示的数据。 2.Kafka 环境准备 调整Kafka内存占用等参数&#xff0c;暴露JMX JMX(Java Management Extensions)是一个为应用程序植入管理功能的框架。JMX是一套标准的代理和…

在GeoTools中的Shapefile属性表读取效率之Shp与Dbf对比

目录 前言 一、POI测试数据简介 1、选用的POI数据 2、关于数据的属性数据 二、属性数据读取的两种方式实现 1、基于DbaseFileReader的读取 2、基于SimpleFeatureSource的读取 三、实际运行对比 1、内存和CPU占用情况 2、运行耗时情况 四、总结 前言 众所周知&#x…

《向量数据库指南》——text-embedding-3-large与Mlivus Cloud打造语义搜索新纪元

使用text-embedding-3-large生成向量并将向量插入Mlivus Cloud实现高效语义搜索的深度解析与实战操作 在数字化时代,数据的处理和存储方式正在经历前所未有的变革。特别是随着大数据和人工智能技术的快速发展,向量数据库作为一种新型的数据存储和查询方式,正逐渐受到越来越…

系统架构设计师教程 第2章 2.6 计算机语言 笔记

2.6计算机语言 ★★★★☆ 2.6.1计算机语言的组成 计算机语言 (Computer Language) 是指用于人与计算机之间交流的一种语言&#xff0c;是人与计算机之间传递信息的媒介。 计算机语言主要由一套指令组成&#xff0c;指令一般包括表达式、流程控制和集合三大部分内容。 表达…

Selenium爬虫技术:如何模拟鼠标悬停抓取动态内容

介绍 在当今数据驱动的世界中&#xff0c;抓取动态网页内容变得越来越重要&#xff0c;尤其是像抖音这样的社交平台&#xff0c;动态加载的评论等内容需要通过特定的方式来获取。传统的静态爬虫方法难以处理这些由JavaScript生成的动态内容&#xff0c;Selenium爬虫技术则是一…

测试造数,excel转insert语句

目录 excel转sql的insert语句一、背景二、直接上代码 excel转sql的insert语句 一、背景 在实际测试工作中&#xff0c;需要频繁地进行测试造数并插入数据库验证&#xff0c;常规的手写sql语句过于浪费时间&#xff0c;为此简单写个脚本&#xff0c;通过excel来造数&#xff0…

Flink CDC系列之:调研应用Flink CDC将 ELT 从 MySQL 流式传输到 StarRocks方案

Flink CDC系列之&#xff1a;调研应用Flink CDC将 ELT 从 MySQL 流式传输到 StarRocks方案 准备准备 Flink Standalone 集群准备 docker compose为 MySQL 准备记录使用 Flink CDC CLI 提交作业 同步架构和数据更改路由变更清理 本教程将展示如何使用 Flink CDC 快速构建从 MySQ…

Rust 力扣 - 1. 两数相加

文章目录 题目描述题解思路题解代码题目链接 题目描述 题解思路 我们使用一个全局的备忘录&#xff0c;然后我们遍历数组&#xff0c;如果当前元素在备忘录里面找到了&#xff0c;就返回备忘录里面记录的下标和当前下标记录&#xff0c;没找到就把当前元素匹配的元素和当前元素…

DEVOPS: 容器与虚拟化与云原生

概述 传统虚拟机&#xff0c;利用 hypervisor&#xff0c;模拟出独立的硬件和系统&#xff0c;在此之上创建应用虚拟机是一个主机模拟出多个主机虚拟机需要先拥有独立的系统docker 是把应用及配套环境独立打包成一个单位docker 是在主机系统中建立多个应用及配套环境docker 是…

【WiFi7】 支持wifi7的手机

数据来源 Smartphones with WiFi 7 - list of all latest phones 2024 Motorola Moto X50 Ultra 6.7" 1220x2712 Snapdragon 8s Gen 3 16GB RAM 1024 GB 4500 mAh a/b/g/n/ac/6e/7 Sony Xperia 1 VI 6.5" 1080x2340 Snapdragon 8 Gen 3 12GB RAM 512 G…

基于JAVASE的题

字符集合 描述&#xff1a; 每组数据输入一个字符串&#xff0c;字符串最大长度为100&#xff0c;且只包含字母&#xff0c;不可能为空串&#xff0c;区分大小写。 每组数据一行&#xff0c;按字符串原有的字符顺序&#xff0c;输出字符集合&#xff0c;记重复出现并靠后的字…

【数学二】多元函数积分学-重积分-二重积分定义、性质、计算

考试要求 1、了解多元函数的概念&#xff0c;了解二元函数的几何意义. 2、了解二元函数的极限与连续的概念&#xff0c;了解有界闭区域上二元连续函数的性质. 3、了解多元函数偏导数与全微分的概念&#xff0c;会求多元复合函数一阶、二阶偏导数&#xff0c;会求全微分&#x…

以 6502 为例讲讲怎么阅读 CPU 电路图

开篇 你是否曾对 CPU 的工作原理充满好奇&#xff0c;以及简单的晶体管又是如何组成逻辑门&#xff0c;进而构建出复杂的逻辑电路实现&#xff1f;本文将以知名的 6502 CPU 的电路图为例&#xff0c;介绍如何阅读 CPU 电路图&#xff0c;并向你演示如何从晶体管电路还原出逻辑…

RISC-V笔记——显式同步

1. 前言 RISC-V的RVWMO模型主要包含了preserved program order、load value axiom、atomicity axiom、progress axiom和I/O Ordering。今天主要记录下preserved program order(保留程序顺序)中的Explicit Synchronization(显示同步)。 2. 显示同步 显示同步指的是&#xff1a…

ArcGIS计算落入面图层中的线的长度或面的面积

本文介绍在ArcMap软件中&#xff0c;计算落入某个指定矢量面图层中的另一个线图层的长度、面图层的面积等指标的方法。 如下图所示&#xff0c;现在有2个矢量要素集&#xff0c;其中一个为面要素&#xff0c;表示某些区域&#xff1b;另一个为线要素&#xff0c;表示道路路网。…

软考系统分析师知识点二四:错题集11-20

前言 今年报考了11月份的软考高级&#xff1a;系统分析师。 考试时间&#xff1a;11月9日。 倒计时&#xff1a;13天。 目标&#xff1a;优先应试&#xff0c;其次学习&#xff0c;再次实践。 复习计划第二阶段&#xff1a;刷选择题&#xff0c;搜集错题集反复查看&#x…

Pr 视频效果:波形变形

视频效果/扭曲/波形变形 Distort/Wave Warp 波形变形 Wave Warp效果用于在剪辑上创建类似波浪的动态变形效果。 此效果会自动动画化&#xff0c;波形以恒定速度移动。要改变速度或停止波动&#xff0c;需要设置关键帧。 ◆ ◆ ◆ 效果选项说明 通过调整波形的类型、高度、宽度…