Redis系列之事务

news2024/11/12 7:11:08

概述

Redis事务提供一种将多个命令打包,然后一次性、按顺序地执行的机制,在事务执行的期间不会主动中断,服务器在执行完事务中的所有命令之后,才会继续处理其他客户端的其他命令。

三个重要的保证:

  • 批量操作在发送EXEC命令前被放入队列缓存
  • 收到EXEC命令后进入事务执行,事务中任意命令执行失败,其余的命令依然被执行
  • 在事务执行过程,其他客户端提交的命令请求不会插入到事务执行命令序列中

Redis中的事务是一组命令的集合,事务也是Redis最小的执行单位,一个事务中的命令要么都执行,要么都不执行。

Redis事务由5个命令来实现:

  1. MULTI:标记一个事务块的开始。开启Redis事务,置客户端为事务态
  2. EXEC:提交事务,执行从MULTI到此命令前的命令队列,置客户端为非事务态
  3. DISCARD:取消事务,置客户端为非事务态
  4. WATCH:监视键值对,作用时如果事务提交EXEC时发现监视的监视对发生变化,事务将被取消
  5. UNWATCH:取消WATCH命令对所有Key的监视

事务从开始到执行会经历以下三个阶段:

  • 开始事务
  • 命令入队
  • 执行事务

MULTI标记事务的开始,将客户端状态的flags属性的REDIS_MULTI选项打开,让客户端从非事务状态切换到事务状态。

命令入队

Redis客户端处理非事务状态时,命令会立即被服务端执行。但是事务状态下,如果客户端发送的命令是上面四个命令其一,则服务器立即执行;除此之外,服务器并不立即执行命令,而是将命令放入事务队列里面,向客户端返回QUEUED回复。
在这里插入图片描述

WATCH

Redis使用WATCH命令监视给定的Key,当EXEC时如果监视的Key从调用WATCH后发生过变化,则整个事务会失败。也可以调用WATCH多次监视多个Key,这样就可以对指定的Key加乐观锁。注意WATCH的Key是对整个连接有效的,事务也一样。如果连接断开,监视和事务都会被自动清除。当然EXEC,DISCARD,UNWATCH命令都会清除连接中的所有监视。

实战

本文使用的Redis版本为Windows下7.4.0版本。

empty array

执行MULTI命令后没有其他命令,直接输入EXEC命令,不报错:

127.0.0.1:6379> multi
OK
127.0.0.1:6379(TX)> exec
(empty array)

WATCH

可用于实现类似于乐观锁效果,即CAS,compare and set。

WATCH用于监视Key是否被改动过,支持同时监视多个Key,只要还没真正触发事务,WATCH都会尽职尽责的监视。当多个线程更新同一个Key值时,会跟原值做比较,一旦发现它被修改过,则拒绝执行命令,执行EXEC时就会返回nil,表示事务无法触发。

双击redis-cli.exe打开一个命令行窗口,依次执行如下命令:

127.0.0.1:6379> watch age
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379(TX)> set age 31
QUEUED

双击redis-cli.exe打开另一个命令行窗口,执行如下命令:

127.0.0.1:6379> set age 32
OK

回到第一个窗口(客户端),提交EXEC命令:

127.0.0.1:6379(TX)> exec
(nil)

命令返回(nil),表示事务无法触发。因为另外一个客户端通过set命令更新过Key

哪怕是值不变,有过set key动作就会更新更新时间戳字段(猜测),和MVCC机制比较类似,Redis源码待调研。

客户端一执行:

127.0.0.1:6379> set age 11
OK
127.0.0.1:6379> watch age
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379(TX)> set age 12
QUEUED

客户端二执行:

127.0.0.1:6379> get age
"11" # 在客户端一执行set后,可get获取
127.0.0.1:6379> set age 11
OK # 在客户端一执行watch后,尝试set更新到相同的年龄

客户端一执行:

127.0.0.1:6379(TX)> exec
(nil)

执行结果也是(nil)。

事务错误

两类错误:

  • 调用EXEC之前的错误
  • 调用EXEC之后的错误

EXEC执行前出错:如语法有误,内存不足导致。只要出现某个命令无法成功写入缓冲队列的情况,Redis都会进行记录,在客户端调用EXEC时,Redis会拒绝执行这一事务。

127.0.0.1:6379> multi
OK
127.0.0.1:6379(TX)> he
(error) ERR unknown command 'he', with args beginning with:
127.0.0.1:6379(TX)> set he he
QUEUED
127.0.0.1:6379(TX)> exec
(error) EXECABORT Transaction discarded because of previous errors.

EXEC执行后出错:Redis不会理睬这些错误,而是继续向下执行事务中的其他命令。对于应用层面的错误,并不是Redis需要考虑和处理的问题,所以事务中如果某一条命令执行失败,并不会影响接下来的其他命令的执行。

127.0.0.1:6379> multi
OK
127.0.0.1:6379(TX)> set age 34
QUEUED
127.0.0.1:6379(TX)> sadd age 35
QUEUED
127.0.0.1:6379(TX)> set age 35
QUEUED
127.0.0.1:6379(TX)> exec
1) OK
2) (error) WRONGTYPE Operation against a key holding the wrong kind of value
3) OK
(0.53s)
127.0.0.1:6379> get age
"35"

这里可以得出一个很重要的结论:在执行事务时某个命令执行失败,并不会影响其他命令的执行,即Redis 的事务并不会回滚。

Lua集成

Lua脚本集成,参考Redis系列之Lua脚本整合。

ACID

传统事务四个核心特性,即ACID。为了保持简单,Redis事务保证其中的一致性和隔离性;不满足原子性和持久性;

原子性

在执行事务命令时,在命令入队时,Redis检测事务里的命令是否正确,即是否有语法错误,如果不正确则会产生错误。事务里的命令是批量提交执行的,也就是命令还没执行,当然也就不存在回滚一说;

当命令格式正确,而因为操作数据结构引起的错误,则该命令执行时才会出现错误,而其之前和之后的命令都会被正常执行。

参考You Don’t Need Transaction Rollbacks in Redis,以及Redis Transactions:

Redis does not support rollbacks of transactions since supporting rollbacks would have a significant impact on the simplicity and performance of Redis.

翻译:支持回滚会对 Redis 的简单性和性能产生重大影响。

一致性

一致性指的就是事务执行前后的数据符合数据库的定义和要求。

Redis符合要求,不论是发生语法错误还是运行时错误,错误的命令均不会被执行。

隔离性

多个事务并发执行,各个事务之间不会互相影响。原因:Redis事务不会中断,且是单线程执行事务。

持久性

对于事务的执行来说,如果Redis开启AOF持久化,那么一旦事务被成功执行,事务中的命令就会通过write命令一次性写到磁盘中去,如果在向磁盘中写的过程中恰好出现断电、硬件故障等问题,可能出现只有部分命令进行AOF持久化,这时AOF文件就会出现不完整的情况,这时可使用redis-check-aof工具将AOF文件中不完整的信息移除,确保AOF文件完整可用。

原理

Redis中每个客户端都有记录当前客户端的事务状态multiState,客户端client定义,在server.h源码里:

typedef struct client {
	uint64_t id; // 客户端唯一id
	multiState mstate; // MULTI和EXEC状态(即事务状态)
	// 省略其他属性
} client;

multiState定义如下:

typedef struct multiState {
	multiCmd *commands; // 存储命令的FIFO队列
	int count; // 命令总数
	// 省略其他属性
} multiState;

multiCmd是一个队列,用来接收并存储开启事务之后发送的命令,定义如下:

typedef struct multiCmd {
	robj **argv; // 用来存储参数的数组
	int argv_len; // 数组长度
	int argc; // 参数的数量
	struct redisCommand *cmd; // 命令指针
} multiCmd;

类结构图:
在这里插入图片描述

拓展

Redis事务在真实业务场景中的应用

  • 批量操作:如果你需要对多个键进行原子性修改,Redis事务可以确保这些操作在没有被中断的情况下执行。例如,批量更新用户积分、库存等;
  • 乐观锁场景:在高并发环境下,使用WATCH可以监控某些关键键的变化,防止并发修改带来的数据不一致问题;
  • 复杂多键操作:在需要对多个键进行依赖性操作时,比如从一个账户扣款同时向另一个账户转账,Redis事务可以确保这类操作的完整性。

局限性:

  • 缺乏回滚机制:如果事务中的某个命令执行失败,Redis不会回滚已经执行的命令,这在某些需要严格数据一致性的场景中是个问题;
  • 命令执行顺序无法调整:事务中的命令执行顺序是固定的,无法在运行时调整,如果某些条件改变,无法动态改变执行顺序;
  • 性能开销:由于事务的执行需要在内存中排队,如果队列中的命令较多,可能导致阻塞和性能问题。

参考

  • Redis事务
  • Redis事务

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

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

相关文章

el-table中el-select俩列共用同一数据并且选择不能相同

需求:el-table中有el-select,el-select的下拉数据源是相同的,但是要同一行的俩列数据选择不相同,如果相同需要提示并且清空数据 1.效果 2.主要代码详解 主要是 change"handleChange(后人员, scope.$index, scope.row.new_use…

关于侵害用户权益行为app的通报的一些思考

8月16日上海市通信管理局官方微信公众号“上海通信圈”发布《上海市通信管理局关于侵害用户权益行为app的通报(2024年第一批)》。本次app通报为2024年第一批。内容显示本次共通报26款移动互联网应用程序涉及app和小程序。 应用来源:本次检测…

【深海王国】小学生都能玩的语音模块?番外1:ASRPRO控制继电器开关

Hi~ (o ^ ^ o)♪, 各位深海王国的同志们,早上下午晚上凌晨好呀~ 辛苦工作的你今天也辛苦啦(/≧ω) 今天大都督为大家带来语音模块的番外系列——ASRPRO控制继电器开关,帮你学会使用ASRPRO控制继电器开关电器元件,let’s go! 番外…

学习大数据DAY39 基于 hive 的 SQL语句

目录 hive 介绍以及应用 上机练习 hive 介绍以及应用 --查看数据库 show database db_hive --过滤查看数据库 show databases like db_hive*; --查看详情 desc database db_hive desc database extended db_hive; --查看表 show tables; --查看表列详情 desc dept…

小学二年级数学精选试题

小学二年级数学精选试题

leetcode 089 打家劫舍

leetcode 089 打家劫舍 题目 一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响小偷偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。 给定…

【计算机网络】网络版本计算器

此前我们关于TCP协议一直写的都是直接recv或者read,有了字节流的概念后,我们知道这样直接读可能会出错,所以我们如何进行分割完整报文?这就需要报头来解决了! 但当前我们先不谈这个话题,先从头开始。 将会…

GlobalMapper-大疆的航点kmz转航线文件展示空间轨迹

0序: 在大疆遥控器或者司空2中设置航线,都是一个个的航点,如果把航点转为航线,在三维地球中显示其空间效果。用于分析和实际物体的距离,或者展示该航线都做了哪些方面的考虑。 如何把一堆点连城一条线? 本…

进程相关命令和函数

查询进程相关命令 ps aux 查看进程相关信息 1.就绪态、运行态 R 2.睡眠态、等待态 可唤醒等待态 S 不可唤醒等待态 D 3.停止态 T 4.僵尸态 Z 5.结束态 top 根据CPU占用率查看进程相关信息 kill 和killall kill和killall发送一个信号 kill -2 PID 15 发送信号PID对应的进程&…

又一实锤 美元丧钟敲响

文|琥珀食酒社 作者 | 积溪 咱们又要见证历史了 之前我说美元霸权快终结了 没想到马上又来了一个实锤 就在刚刚 “159个国家将采用金砖国家新支付系统“的消息 冲上热搜 据大毛媒体爆料 这个新支付系统 将在今年10月份上线 替代现有的swift系统 这是要挖…

nginx的详细介绍及配置

Nginx(发音为“engine X”)是一个高性能的HTTP和反向代理服务器,也是一个IMAP/POP3/SMTP代理服务器。Nginx以其稳定性、丰富的功能集、简单的配置和低资源消耗而闻名。它最初由俄罗斯人Igor Sysoev编写,并于2004年首次公开发布。N…

解决旧版CMS内容管理无法登录的问题

最近遇到了输入正确的账户密码,旧版的CMS内容管理的平台提示登录成功却无法跳转的问题 遇到这种情况请不要慌!!! 请按照下面的步骤解决问题: 1.点击账号管理 2.点击右上角的返回旧版控制台 3.点击cloud1环境 4.点击扩…

财务会计与管理会计(十一)

文章目录 快速切换日记账余额SUMPRODUCT、LOOKUP函数应用 销售业绩分段统计表SUMPRODUCT函数的应用 自动打印发票签收单VLOOKUP函数的应用 快速切换日记账余额 SUMPRODUCT、LOOKUP函数应用 C2SUMPRODUCT((A5:A100B2)*C5:C100) D2SUMPRODUCT((A5:A100B2)*D5:D100) E4公式1&…

javaweb学习之HTML(一)

推荐学习使用网站 w3school 在线教程 认识HTML HTML(HyperText Markup Language)是超文本标记语言,它是一个用于创建网页和网页应用程序的标准标记语言。HTML文档由一系列的元素(elements)组成,这些元素通…

大模型日报|10 篇必读的大模型论文

大家好,今日必读的大模型论文来啦! 1.斯坦福推出大模型网络安全能力和风险评估框架 Cybench 用于网络安全的语言模型智能体(agent)能够自主识别漏洞并执行漏洞利用,有可能对现实世界造成影响。政策制定者、模型提供者…

海外媒体投稿:怎样在法国媒体发稿宣传中获得成功

法国是一个充满机遇的销售市场,而媒体发稿营销推广是企业在法国市场里扩张曝光度和提升知名度的有效途径。下面我们就共享如何运用低投资得到高收益的办法,帮助企业在法国媒体发稿推广过程中获得成功。 第一步:掌握目标群体在进行法国媒体发稿…

HCIP-交换实验

根据实验要求,完成实验内容: 实验拓扑图如下所示 : 搭建拓补图: LSW1,LSW2: [LS1]interface Eth-Trunk 0 [LS1-Eth-Trunk0]q [LS1]interface g0/0/3 [LS1-GigabitEthernet0/0/3]eth-trunk 0 [LS1]interf…

微信支付商家转账到零钱申请必过方案总结

商家在申请商家转账到零钱时总会遇到各种原因的驳回,不少商家不断的修改又产生新的驳回原因从而导致工期无限延长,本文根据我们上万次成功申请商家转账到零钱的经验整理,帮助商家可以快速过审: 准备工作和注意事项 - 确认主体资格…

mq-fanout交换机

交换机 交换机是什么?步骤 交换机本身具备路由功能 消息先发到交换机,交换机在路由到队列,消费者监听队列拿到消息 广播模式是什么 是什么 例如:每个微服务创建队列,订单服务只启动1台,1个消费者,订单 怎么创建 创建一个队列 -交换机里type-选择模式(广播模式) 在交换…

AMD为何花49亿美元收购ZT Systems?

是的,是不是很震惊! 苏妈再次出手,在美国当地时间8月19日,AMD同意用价值49亿美元的现金和股票收购ZT Systems——这笔费用超过了AMD 2024年预期在数据中心GPU销售总额。 从收购的金额我们就能看出这笔收购的重要性。 但为什么AM…