【Redis】深入理解 Redis 事务机制

2023-11-03


前言

一、回顾 MySQL 事务

1.1 MySQL 事务的概念与特性

MySQL事务是一种用于管理数据库操作的机制,它确保一组相关的 SQL 操作要么全部成功执行,要么全部失败,从而维护数据的一致性和完整性。事务是数据库管理系统中的核心概念之一,它通常遵循 ACID 属性:

  1. 原子性(Atomicity): 事务是一个原子操作,要么全部执行成功,要么全部失败。如果其中任何一部分操作失败,整个事务将被回滚,数据库状态将保持不变。

  2. 一致性(Consistency): 事务的执行将数据库从一个一致的状态转移到另一个一致的状态。这意味着事务执行后,数据库必须满足事先定义的完整性约束。

  3. 隔离性(Isolation): 隔离性定义了多个并发事务之间的相互影响程度。不同的隔离级别提供不同的隔离程度,包括读未提交、读已提交、可重复读和串行化等级。

  4. 持久性(Durability): 一旦事务被提交,其结果将永久存储在数据库中,并在系统故障后保持不变。

1.1 MySQL 事务的管理

在MySQL中,可以使用以下关键字来管理事务:

  • BEGIN:开始一个新的事务。
  • COMMIT:提交事务,将更改保存到数据库。
  • ROLLBACK:回滚事务,撤销未提交的更改。
  • SAVEPOINT:创建一个保存点,可以在事务中的特定位置回滚。
  • SET TRANSACTION:设置事务的属性,如隔离级别。

以下是一个简单的MySQL事务示例:

BEGIN;  -- 开始事务

-- 在事务中执行一些SQL操作
INSERT INTO users (id, username) VALUES (1, 'user1');
UPDATE accounts SET balance = balance - 100 WHERE user_id = 1;

-- 如果一切正常,提交事务
COMMIT;

如果在事务执行期间发生错误或者需要取消事务,可以使用ROLLBACK命令来回滚事务,这将撤销所有在事务中的更改。

BEGIN;  -- 开始事务

-- 在事务中执行一些SQL操作
INSERT INTO users (id, username) VALUES (2, 'user2');
-- 发生错误,回滚事务
ROLLBACK;

使用事务可以确保数据库的数据完整性,特别是在多个用户同时访问数据库时。根据具体的应用场景和需求,可以选择不同的隔离级别,以平衡并发性和一致性之间的需求。在实际应用中,正确使用事务是确保数据的一致性和可靠性的关键。

二、对 Redis 事务的认识

2.1 什么是 Redis 的事务

2.1.1 Redis 事务的概念

简单来说,Redis事务 允许将一组 Redis 命令组合成一个单独的、不可中断的操作序列。这意味着,一旦开始了一个 Redis 事务,任何在事务执行期间的其他客户端的命令都不会中断这个事务,而是会排队等待执行,直到事务被提交或取消执行。

2.1.2 对 Redis 事务的深入理解

  • Redis 事务的核心概念涉及在 Redis 服务器上创建一个称为 "事务队列" 的缓冲区。当开启一个事务后,所有与该事务相关的命令都将按顺序排队进入该队列。只有当发送执行事务的命令时,队列中的命令才会以原子的方式依次执行,这确保了这组命令要么全部成功,要么全部失败。

  • 在事务队列中,可以包括任意数量的 Redis 命令,包括读取和写入操作,以便进行一系列复杂的操作。然而,需要注意的是,Redis 事务并不支持像传统数据库那样的隔离级别和回滚机制。因此,应用程序需要自行处理错误和回滚逻辑。

  • 未收到执行命令的事务在 Redis 服务器中处于排队等待状态,虽然将命令发送给了服务器,但并没有执行,同时也不会影响其他客户端命令的正常执行。

总之,Redis 事务为提供了一种 将多个命令打包成一个原子操作的能力 ,这在需要 确保一系列操作的一致性时 非常有用。然而,它与传统数据库的事务有一些区别,特别是在隔离性和持久性方面。

2.2 Redis 事务与 MySQL 事务的比较

虽然 Redis 和 MySQL 都涉及事务的概念,但在实现和应用方面存在一些关键差异。

2.2.1 事务的粒度

Redis事务: Redis 事务通常以单个命令的粒度工作。多个 Redis 命令可以放入一个事务中,但每个命令本身是不可分割的。这允许执行一系列简单的操作,但不能跨多个 Redis 命令执行复杂的事务。

MySQL事务: MySQL 事务具有更广泛的粒度,允许跨多个 SQ L语句执行复杂的事务,包括事务的开始和结束。

2.2.2 ACID 属性

Redis事务: Redis 事务支持原子性(Atomicity)和一致性(Consistency),确保一组命令要么全部成功,要么全部失败,并在事务执行后维护数据的一致性。但 Redis 不支持传统数据库中的隔离性(Isolation)和持久性(Durability)。

MySQL事务: MySQL 事务支持完整的 ACID 属性,包括原子性、一致性、隔离性和持久性。这使得 MySQL 事务在需要严格事务完整性的应用中非常有用,如金融和电子商务系统。

2.2.3 并发控制

Redis事务: Redis 事务是单线程的,一次只能执行一个事务。这限制了并发性,因为其他客户端的命令必须排队等待执行。同时 Redis 使用乐观锁定来控制并发。

MySQL事务: MySQL 具有强大的并发控制机制,支持多个事务同时执行,可以根据需要选择不同的隔离级别,从而平衡并发性和一致性。

2.2.4 错误处理和回滚

Redis事务: Redis 事务提供了回滚操作的能力,可以使用 DISCARD 命令来取消当前事务并清除已排队的命令。但 Redis 不会自动回滚事务中的错误命令。

MySQL事务: MySQL事务支持显式的回滚操作,可以使用 ROLLBACK 来撤销已执行的事务中的命令,并恢复到事务开始之前的状态。

2.2.5 应用场景

Redis事务: Redis 事务通常用于缓存、队列、计数器等特定用例,其中需要简单的原子操作,但不强调严格的隔离性和持久性

MySQL事务: MySQL 事务广泛用于支持事务完整性的应用程序,如电子商务、金融系统等,这些应用需要强大的 ACID 支持。

总之,Redis事务和MySQL事务在粒度、ACID属性、并发控制、错误处理和应用场景等方面存在重要差异。选择使用哪种类型的事务取决于项目需求和性能要求。在某些情况下,Redis和MySQL可以共同使用,以满足不同类型的事务需求。

三、Redis 事务相关命令

Redis 事务是一种强大的功能,允许我们将一系列 Redis 命令打包在一起,以确保它们要么全部成功执行,要么全部失败。在 Redis 中,有一些关键的命令用于处理事务,包括 MULTIEXECDISCARDWATCHUNWATCH。下面将详细介绍这些命令的作用和用法。

3.1 MULTI

MULTI 命令用于开启一个事务。在执行 MULTI 命令后,Redis 会进入事务模式,接下来的命令都会被加入到事务队列中等待执行。如果执行成功,MULTI 命令会返回 “OK”。

实例:

127.0.0.1:6379> MULTI
OK

3.2 EXEC

EXEC 命令用于执行事务中的命令队列。在执行 EXEC 命令时,Redis 会按照事务队列中命令的顺序,以原子的方式依次执行这些命令。如果事务中的所有命令都执行成功,EXEC 命令返回一个包含每个命令执行结果的数组;如果有命令执行失败,事务中的所有命令都会被取消。

实例:

127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> SET k1 1
QUEUED
127.0.0.1:6379> SET k2 2
QUEUED
127.0.0.1:6379> SET k3 3
QUEUED
127.0.0.1:6379> EXEC
1) OK
2) OK
3) OK

3.3 DISCARD

DISCARD 命令用于放弃当前事务。执行 DISCARD 命令会清空事务队列中的所有命令,之前的操作都不会被真正执行。

实例:

127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> SET k1 1
QUEUED
127.0.0.1:6379> SET k2 2
QUEUED
127.0.0.1:6379> DISCARD
OK
127.0.0.1:6379> GET k1
(nil)
127.0.0.1:6379> GET k2
(nil)

3.4 WATCH

在执行事务时,如果某个事务中的键被其他客户端修改,可能会导致数据不一致的问题。WATCH 命令用于解决这个问题,它可以监控一组指定的键,如果这些键在事务执行前被其他客户端修改,事务将被取消。

实例:

# 客户端1 开始监控 k1
127.0.0.1:6379> WATCH k1
OK

# 客户端2 修改 k1
127.0.0.1:6379> SET k1 100
OK

# 客户端1 执行事务,但由于 k1 被修改,事务将被取消
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> SET k1 200
QUEUED
127.0.0.1:6379> EXEC
(nil)
# 获取 k1 的值
127.0.0.1:6379> GET k1
"100"

WATCH原理:

WATCH 的原理可以简单概括为以下几个步骤:

  1. 客户端执行 WATCH 命令并指定要监视的键。
  2. Redis 在服务器端创建一个监视器(Watcher)来监视这些键。监视器会记录被监视键的当前状态,通常是版本号或时间戳
  3. 客户端进入事务模式,可以执行多个命令,但这些命令不会立即执行,而是进入一个队列中等待。
  4. 在执行事务之前,客户端要求服务器检查监视器中被监视键的状态是否发生变化。这是通过比较监视器中的状态与当前键的状态来完成的。
  5. 如果监视器发现被监视键的状态在执行事务之前已经发生变化,它会通知客户端取消事务。这是乐观锁的核心思想:如果其他客户端在执行 WATCHEXEC 之间修改了被监视的键,那么事务将失败。
  6. 如果监视器未发现变化,客户端可以执行事务中的命令,这些命令会按顺序执行。

总之,WATCH 的原理是通过在服务器端创建监视器来监控一组键的状态,并在执行事务前检查这些键的状态是否发生变化。如果有其他客户端修改了被监视键,事务将被取消,以确保数据的一致性。这使得 Redis 能够在并发环境中实现事务操作,而不会引发竞态条件等问题。

3.5 UNWATCH

UNWATCH 命令用于取消对键的监控,是 WATCH 命令的逆操作。如果你不再需要监控某些键,可以使用 UNWATCH 来取消监控。

127.0.0.1:6379> set key 1
OK
127.0.0.1:6379> WATCH key
OK
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> set key 2
QUEUED
127.0.0.1:6379> set key 3
QUEUED
127.0.0.1:6379> DISCARD
OK
127.0.0.1:6379> UNWATCH
OK
127.0.0.1:6379> 

以上就是 Redis 事务相关命令的详细介绍。通过合理使用这些命令,就可以构建出安全、可靠的事务操作,确保数据的一致性和完整性。当然,在使用事务时,需要根据具体的业务需求和情况来决定是否使用监控命令 WATCH

四、总结

在本文中,深入探讨了Redis事务的概念和相关命令,以及 Redis 事务与 MySQL 事务的比较。以下是本文的主要要点总结:

  1. Redis 事务的核心概念: Redis 事务允许将多个 Redis 命令打包成一个单一、不可中断的操作序列。这确保了这些命令要么全部成功执行,要么全部失败。

  2. Redis 事务相关命令: Redis 提供了一组关键命令来管理事务,包括MULTI(开始事务)、EXEC(提交事务)、DISCARD(取消事务)、WATCH(监视键变化)、和UNWATCH(取消监视)。

  3. Redis 事务与 MySQL 事务的比较: Redis 事务与 MySQL 事务在事务粒度、ACID 属性、并发控制、错误处理和应用场景等方面存在不同。Redis 事务通常用于简单的原子操作,而 MySQL 事务支持更广泛的 ACID 属性,适用于需要强大事务完整性的应用。

  4. Redis 事务的限制: Redis 事务不支持传统数据库中的隔离级别和持久性,需要应用程序自行处理错误和回滚逻辑。

在选择使用 Redis 事务还是 MySQL 事务时,应根据项目需求和性能要求权衡不同的特性和限制。了解 Redis 事务的工作原理和使用方式,可以帮助我们更好地利用 Redis 的事务功能。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

【Redis】深入理解 Redis 事务机制 的相关文章

  • PooledRedisClientManager 未释放连接

    我将 json 数据列表存储在 redis 中并使用 ServiceStack c 客户端访问它 我本质上是在管理自己的外键 我在其中存储zrangeid 我使用应用程序内部的接口从zrange然后从 Redis 获取底层 json 对象并
  • 如何在多个Lua State(多线程)之间传递数据?

    我在中启动Redis连接池redis lua 通过从 C 调用 我得到了redis lua state 此 Lua 状态全局启动一次 仅在其他线程中启动get从中 当有一个 HTTP 请求 工作线程 时 我需要从redis lua stat
  • 是否有可嵌入的 Java 替代 Redis?

    根据这个线程 https stackoverflow com questions 3047010 best redis library for java 如果我想从Java中使用Redis Jedis是最好的选择 然而 我想知道是否有任何库
  • 在 sidekiq 上配置 redis 身份验证

    我想我错过了一些东西 因为我在文档中找不到如何编写 redis 实例的用户名和密码以与 sidekiq 一起使用 有没有办法做到这一点 或者是通过 ENV 变量 Sidekiq 将无法识别的 Redis 选项直接传递给 Redis 驱动程序
  • Redis SYNC 套接字上的错误情况:连接被拒绝

    在我的 django 应用程序中使用 celery 和 redis 一切都工作正常 直到我遇到了问题 redis 文件的位置已更改 redis 无法访问它们 经过查找 原来这是由于网络随机攻击造成的 需要添加confg 我添加文件后 一段时
  • 有没有办法在 ruby​​ 中重新定义 []=+

    我正在尝试编写一个简单的 DSL 针对 Redis 并且我想自己定义 I have def key val redis zadd name val key end 我想定义 def key val redis zincrby name va
  • 如何在Redis中从hmset()切换到hset()?

    我收到弃用警告 即 Redis hmset 已弃用 请改用 Redis hset 但是 hset 采用第三个参数 我不知道是什么name应该是 info users 10 timestamp datetime utcnow strftime
  • Redis Cluster 与 Pub/Sub 中的 ZeroMQ,用于水平扩展的分布式系统

    如果我要设计一个巨大的分布式系统 其吞吐量应随系统中的订阅者数量和通道数量线性扩展 哪个会更好 1 Redis集群 仅适用于Redis 3 0 alpha 如果是集群模式 您可以在一个节点上发布并在另一个完全不同的节点上订阅 消息将传播并到
  • 为什么 Redis TimeSeries 不捕获聚合中的最后一个元素?

    我试图了解 Redis 的时间序列规则创建的工作原理 但我很困惑为什么 Redis 会忽略聚合中的最后一项 并想知道这是否是预期的行为 我在中创建了示例代码redis cli为了显示 127 0 0 1 6379 gt FLUSHALL O
  • 有没有办法用Lettuce自动发现Redis集群中新的集群节点IP

    我有一个Redis集群 3主3从 运行在一个库伯内斯簇 该集群通过Kubernetes 服务 Kube 服务 我将我的应用程序服务器连接到 Redis 集群 使用Kube 服务作为 URI 通过 Redis 的 Lettuce java 客
  • 如何使 Redis 缓存中数据层次结构(树)的部分内容无效

    我有一些产品数据 需要在 Redis 缓存中存储多个版本 数据由 JSON 序列化对象组成 获取普通 基本 数据的过程很昂贵 将其定制为不同版本的过程也很昂贵 因此我想缓存所有版本以尽可能进行优化 数据结构看起来像这样 BaseProduc
  • 想要在后台不间断地运行redis-server

    我已经下载了 redis 2 6 16 tar gz 文件并安装成功 安装后我运行 src redis server 它工作正常 但我不想每次都手动运行 src redis server 而是希望 redis server 作为后台进程持续
  • Scala 使用的 Redis 客户端库建议

    我正在计划使用 Scala 中的 Redis 实例进行一些工作 并正在寻找有关使用哪些客户端库的建议 理想情况下 如果存在一个好的库 我希望有一个为 Scala 而不是 Java 设计的库 但如果现在这是更好的方法 那么仅使用 Java 客
  • 如何在Redis中只保存一个数据库?

    我是 Redis 新手 有一个与备份相关的问题 目前 我有一个实例在 Windows 服务器上运行 在这个实例中 我当前有一项 工作 将数据存储在一个数据库中 我不想备份这些数据 我必须创造一份新工作 我的第一个想法是将数据存储在另一个数据
  • Redis+Docker+Django - 错误 111 连接被拒绝

    我正在尝试使用 Redis 作为使用 Docker Compose 的 Django 项目的 Celery 代理 我无法弄清楚我到底做错了什么 但尽管控制台日志消息告诉我 Redis 正在运行并接受连接 事实上 当我这样做时 docker
  • Amazon Elasticache Redis 集群 - 无法获取端点

    我需要获取 Amazon Elasticache 中 Redis 集群的终端节点 以下代码适用于 Memcached 集群 但不适用于 Redis import com amazonaws auth AWSCredentials impor
  • Laravel 异常队列最大尝试次数超出

    我创建了一个应用程序来向多个用户发送电子邮件 但在处理大量收件人时遇到问题 该错误出现在failed jobs table Illuminate Queue MaxAttemptsExceededException App Jobs ESe
  • 创建 C++ Redis 模块 - “不导出 RedisModule_OnLoad() 符号”

    我在加载 Redis 模块时遇到一些问题 我只是复制来自的示例https redis io topics modules intro https redis io topics modules intro 但我把它剥下来了 include
  • 节点应用程序之间共享会话?

    我目前有两个独立的节点应用程序在两个不同的端口上运行 但共享相同的后端数据存储 我需要在两个应用程序之间共享用户会话 以便当用户通过一个应用程序登录时 他们的会话可用 并且他们似乎已登录到另一个应用程序 在本例中 它是一个面向公众的网站和一
  • 在 Spring 4 中干掉通用的 RedisTemplate

    我读到你可以拥有 Autowired从 Spring 4 开始泛型 这太棒了 我有一个摘要RedisService我想参加的课程 Autowired一个通用的 RestTemplate 如下所示 public abstract class

随机推荐

  • vmware VSAN 双节点部署

    一 环境 ESxi主机 01 192 168 2 26 ESxi主机 02 192 168 2 27 见证主机 虚拟机 192 168 2 157 部署在ESxi 主机01上 注 此操作官方不推荐 192 168 2 26虚拟交换机配置如下
  • Python中default()函数

    阅读textual inversion代码的时候 遇到这样一个用法 def p losses self x start t noise None noise default noise lambda torch randn like x s
  • 【python】运行/调用/执行/终止/重启.exe文件

    一 运行 调用 执行 打开 exe文件 1 os system cmd command 使用 import os os system cmd command 括号里输入的参数即为在cmd里面输入的内容 具体格式参照这个连接 python中o
  • UE5实现距离测量功能

    文章目录 1 实现目标 2 实现过程 2 1 Widget 2 2 蓝图实现 3 参考资料 1 实现目标 UE5在Runtime环境下测量两个空间点位之间的绝对距离 并支持多段线的距离测量 GIF动图如下所示 2 实现过程 实现原理比较简单
  • Django新增自定义模板函数

    Django新增自定义模板函数 1 创建templatetags文件 2 创建一个 py文件 coding utf 8 from django import template register名称不可改 register template
  • 【数据结构与算法】3、虚拟头节点、动态数组的缩容、动态数组和单链表的复杂度、数组的随机访问

    目录 一 虚拟头节点 二 数组的随机访问 三 动态数组 链表复杂度分析 四 动态数组 add E element 复杂度分析 五 动态数组的缩容 一 虚拟头节点 为了让代码更加精简 统一所有节点的处理逻辑 可以在最前面增加一个虚拟的头节点
  • mybatis-plus设置主键自增 ,获取自增主键id

    第一步 实体类加注解 在主键上加 TableId type IdType AUTO 注解 第二步 在数据库设置主键自增 第二种 可以在mapper插入标签中添加keyProperty id useGeneratedKeys true
  • Courses

    点击打开链接 Problem Description Consider a group of N students and P courses Each student visits zero one or more than one co
  • 网络编程-----socket函数

    1 Socket 函数 访问底层操作系统接口的全部方法 提供服务中心类 简化网络服务器的开发 语法 socket socket family type proto family 套接字家族可以是 AF UNIX 或者 AF INET typ
  • Vue.js 2 渐进式前端框架 的最佳学习方法

    Vue js作为一个后起的前端框架 借鉴了Angular React等现代前端框架 库的诸多特点 并且 取得了相当不错的成绩 Vue js的定位是一个渐进式框架 作者的说法是 与其他框架的区别就是渐进式的想法 也就是Progressive
  • 转:Python2字符编码问题汇总

    这篇文章的部分问题在Python3以后不再存在 老猿只是觉得文章的部分内容还是有参考价值 因此在此原文转发连接 Python2字符编码问题汇总
  • 第三章——Lyapunov理论基础

    文章目录 3 1 非线性系统和平衡点 非线性系统 自治与非自治系统 平衡点 常规运动 3 2 稳定性的概念 稳定性与非稳定性 渐进稳定性和指数稳定性 局部和全局稳定性 3 3 线性化和局部稳定性 3 4 Lyapunov直接法 正定函数和L
  • python的高级变量类型

    1 Python 中数据类型可以分为 数字型 和 非数字型 数字型 整型 int 浮点型 float 布尔型 bool 真 True 非 0 数 非零即真 假 False 0 复数型 complex 主要用于科学计算 例如 平面场问题 波动
  • (C语言)关于浮点数和0比较大小

    对于浮点数a 不能用if a 0 来判断a与0的大小 应该判断a是否位于0附近的一个很小的区间 EPS EPS 中 或者说a的绝对值小于等于一个很小的数EPS 可定义EPS 1e 6 即用if fabs a lt EPS 正确的实数与0的比
  • 【PHP基础知识】——操作Email

    邮件已经成为我们生活中不可或缺的信息沟通方式 时常需要我们去群发或者定时发送一下邮件给指定对象 例如系统的故障报警邮件 批量回复一些服务信息等 因此 将发送邮件功能做到后台可配置或者自动化是程序开发的重要部分 像Java等语言一样 下面我们
  • 看完这篇 教你玩转渗透测试靶机Vulnhub——DriftingBlues-2

    Vulnhub靶机DriftingBlues 1渗透测试详解 Vulnhub靶机介绍 Vulnhub靶机下载 Vulnhub靶机漏洞详解 信息收集 暴力破解 漏洞利用 反弹shell nmap提权 获取flag Vulnhub靶机渗透总结
  • docker 端口映射错误解决方法

    COMMAND FAILED sbin iptables t nat A DOCKER p tcp d 0 0 dport 8111 j DNAT to destination 172 17 0 6 8111 i docker0 faile
  • [Android] 底部菜单布局+PopupWindows实现弹出菜单功能(初级篇)

    这篇文章主要是自己研究如何对底部菜单进行布局 并简单的实现点击不同 按钮 实现图片切换和背景切换的功能 最后通过PopupWindows实现弹出菜单 点击不同按钮能实现不同方法 相当于美图秀秀编辑图片的功能吧 它并没有涉及到Fragment
  • c++ 函数指针

    函数指针基础 1 获取函数的地址 2 声明一个函数指针 3 使用函数指针来调用函数 获取函数指针 函数的地址就是函数名 要将函数作为参数进行传递 必须传递函数名 声明函数指针 声明指针时 必须指定指针指向的数据类型 同样 声明指向函数的指针
  • 【Redis】深入理解 Redis 事务机制

    文章目录 前言 一 回顾 MySQL 事务 1 1 MySQL 事务的概念与特性 1 1 MySQL 事务的管理 二 对 Redis 事务的认识 2 1 什么是 Redis 的事务 2 1 1 Redis 事务的概念 2 1 2 对 Red