【Redis】Redis 事务和事务锁

本文涉及的产品
云数据库 Tair(兼容Redis),内存型 2GB
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
简介: 【Redis】Redis 事务和事务锁

一、事务简介

Redis执行指令过程中,多条连续执行的指令被干扰,打断,插队,这多条连续指令执行的结果可能就会有问题

由于客户端2中断了客户端1两条连续的指令执行,导致客户端1获取到itcast

image.png

redis事务就是一个命令执行的队列,将一系列预定义命令包装成一个整体(一个队列)。当执行时,一次性按照添加顺序依次执行,中间不会被打断或者干扰。

一个队列中,一次性、顺序性、排他性的执行一系列命令

二、事务基本指令

  • multi:设定事务的开启位置,此指令执行后,后续的所有指令均加入到事务中
  • exec:设定事务的结束位置,同时执行事务,与multi成对使用

注意:加入事务的命令暂时进入到任务队列中,并没有立即执行,只有执行exec命令才开始执行

image.png

  • discard:终止当前事务,发生在multi之后,exec之前;当我们把错误指令放入队列后,可以使用discard使multi失效,放弃当前任务队列,中止事务

image.png

三、事务的工作流程

set执行流程:  正常执行,返回执行结果

image.png

multi执行流程:  创建事务队列后返回ok

image.png

创建事务后,set执行流程:  将set指令放入事务队列

image.png

创建事务后,del执行流程:  将del指令放入事务队列

image.png

创建事务后,exec执行流程:  顺序执行事务队列中的指令,并销毁队列

image.png

创建事务后,discard执行流程:  放弃执行队列中的指令,直接销毁队列,返回执行结果

image.png

四、事务中指令出错处理

  1. 开启事务后,如果放入队列的指令存在语法错误,将会执行discard,当前事务队列会被销毁

image.png

  1. 开启事务后,如果放入队列的指令并没有语法错误,但无法执行,比如对string类型进行lpush。这种情况下,会顺序执行所有的指令,无法执行则会给出相应的提示信息,并跳过无法执行的指令,不会立即中断当前事务的执行

image.png

注意:已执行命令对应的数据不会自动回滚,需要程序员自己在代码中实现回滚

五、事务锁

1. 业务场景一:多个客户端想操作同一数据,保证数据不被重复操作

视频中这个监视锁的作用好像有点局限,仅限于多个客户端想对同一数据进行相同的操作,保证数据不被重复操作。如果是想要对数据进行不同的操作呢?这个监视锁的功能好像也能用MySQL中的排它锁和共享锁实现

天猫双11热卖过程中,对已经售罄的货物追加补货,4个业务员都有权限进行补货。补货的操作可能是一系列的操作,牵扯到多个连续操作,如何保障不会重复操作?

我们对需要操作的数据添加监视锁并开启事务,如果exec前监视的数据被修改了,那说明我放入事务队列的指令想要操作的数据被修改了,那这些指令操作的结果就不满足我的预期了。此时仍然输入exec,程序将不会执行exec指令,且放弃当前事务

  • 对key添加监视锁,在事务执行exec前如果key发生了变化,终止事务执行


watch key1 [key2…]          # 必须在开启事务multi前执行
  • 取消对所有key的监视


unwatch                     # 取消所有数据的监视锁

客户端A监视name和age,开启事务,准备执行一系列操作

image.png

客户端B修改客户端A监视的age

image.png

客户端A执行exec,执行失败,此时事务也不存在了

image.png

逻辑上,我们应该先监视数据,然后开启事务准备操作,所以不允许先multi开启事务后watch

image.png

2. 业务场景二:setnx操作一个变量,然后再操作对应数据

很多客户同时抢购天猫超市的同一款商品,如何保证最后一件商品不被多人同时购买?【超卖问题】

分析:  如果我们使用watch监视锁解决,此时一个客户端对商品进行监视,他购买时如果其他客户端购买了(修改了商品数量),他就不能购买(exec),这是不符合逻辑的,只要商品有库存,大家应该允许同时购买,只需要保证购买成功的数量和商品减少的数量相等就行。这种情况下,我们使用分布式锁解决(redis并不提供这种特殊的锁,只是我们利用setnx的特性解决此业务场景,这并不像MySQL的排它锁,上了锁就不能操作指定数据,此处redis所谓的锁只是我们约好的先操作某个变量再操作对应数据,实际上setnx的结果并不影响直接操作对应数据

利用setnx拥有的返回值特征,有值则返回设置失败,无值则返回设置成功


setnx lock-key value   # 这个value不重要,其实这就是利用了setnx,lock-key也只是一个普通名字,这就是设置了一个普通的string变量
  • 对于返回设置成功的,对数据拥有控制权,可以进行下一步操作,其他客户端得先操作这个使用setnx的lock-key,根据返回值判断是否可以进一步操作对应数据
  • 对于返回设置失败的,不具有控制权,则等待

操作完毕通过del释放锁


del lock-key

客户端A获取对num的锁

image.png

客户端B获取对lock-num,失败了,如果失败,我们不允许该客户端操作数据

image.png

客户端A购买完商品释放锁

image.png

客户端B setnx lock-num成功,我们在逻辑上允许该客户端操作num

image.png

3. 业务场景三:给上述setnx的变量设置有效时间

防止锁忘了释放,到达有效时间自动释放该锁变量


expire lock-key second
pexpire lock-kay millisenconds

客户端A setnx一把锁,并设置有效时间

image.png

到达有效时间后,lock-name失效,其他客户端自动拿到锁

image.png

由于操作通常都是微秒或者毫秒级,因此该锁设定时间不宜设置过大。具体时间需要业务测试后确认,例如:

  • 持有锁的操作最长执行时间127ms,最短执行时间7ms
  • 测试百万次最长执行时间对应命令的最大消耗时,测试百万次网络延迟平均耗时
  • 锁时间设定推荐:最大耗时* 120%+平均网络延迟*110%
  • 如果业务最大耗时<<网络平均延迟,通常为2个数量级,取其中单个耗时较长即可



相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore &nbsp; &nbsp; ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库&nbsp;ECS 实例和一台目标数据库&nbsp;RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&amp;RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
相关文章
|
24天前
|
缓存 NoSQL Redis
Redis 事务
10月更文挑战第18天
24 1
|
1月前
|
监控 NoSQL 算法
Redis主从切换,锁失效怎么办?
在分布式系统中,Redis因其高性能和易用性而被广泛应用于缓存、分布式锁等场景。然而,当Redis采用主从架构以实现高可用性和数据冗余时,主从切换可能带来的锁失效问题成为了一个不容忽视的挑战。本文将深入探讨Redis主从切换导致锁失效的原因、影响及解决方案,旨在为大家提供实用的技术干货。
91 5
|
3月前
|
负载均衡 NoSQL 算法
一天五道Java面试题----第十天(简述Redis事务实现--------->负载均衡算法、类型)
这篇文章是关于Java面试中Redis相关问题的笔记,包括Redis事务实现、集群方案、主从复制原理、CAP和BASE理论以及负载均衡算法和类型。
一天五道Java面试题----第十天(简述Redis事务实现--------->负载均衡算法、类型)
|
30天前
|
NoSQL Java API
美团面试:Redis锁如何续期?Redis锁超时,任务没完怎么办?
在40岁老架构师尼恩的读者交流群中,近期有小伙伴在面试一线互联网企业时遇到了关于Redis分布式锁过期及自动续期的问题。尼恩对此进行了系统化的梳理,介绍了两种核心解决方案:一是通过增加版本号实现乐观锁,二是利用watch dog自动续期机制。后者通过后台线程定期检查锁的状态并在必要时延长锁的过期时间,确保锁不会因超时而意外释放。尼恩还分享了详细的代码实现和原理分析,帮助读者深入理解并掌握这些技术点,以便在面试中自信应对相关问题。更多技术细节和面试准备资料可在尼恩的技术文章和《尼恩Java面试宝典》中获取。
美团面试:Redis锁如何续期?Redis锁超时,任务没完怎么办?
|
1月前
|
SQL 分布式计算 NoSQL
大数据-42 Redis 功能扩展 发布/订阅模式 事务相关的内容 Redis弱事务
大数据-42 Redis 功能扩展 发布/订阅模式 事务相关的内容 Redis弱事务
24 2
|
5月前
|
消息中间件 NoSQL Java
Redis系列学习文章分享---第六篇(Redis实战篇--Redis分布式锁+实现思路+误删问题+原子性+lua脚本+Redisson功能介绍+可重入锁+WatchDog机制+multiLock)
Redis系列学习文章分享---第六篇(Redis实战篇--Redis分布式锁+实现思路+误删问题+原子性+lua脚本+Redisson功能介绍+可重入锁+WatchDog机制+multiLock)
227 0
|
1月前
|
NoSQL 关系型数据库 MySQL
Redis 事务特性、原理、具体命令操作全方位诠释 —— 零基础可学习
本文全面阐述了Redis事务的特性、原理、具体命令操作,指出Redis事务具有原子性但不保证一致性、持久性和隔离性,并解释了Redis事务的适用场景和WATCH命令的乐观锁机制。
200 0
Redis 事务特性、原理、具体命令操作全方位诠释 —— 零基础可学习
|
3月前
|
缓存 NoSQL Java
SpringBoot整合Redis、以及缓存穿透、缓存雪崩、缓存击穿的理解、如何添加锁解决缓存击穿问题?分布式情况下如何添加分布式锁
这篇文章介绍了如何在SpringBoot项目中整合Redis,并探讨了缓存穿透、缓存雪崩和缓存击穿的问题以及解决方法。文章还提供了解决缓存击穿问题的加锁示例代码,包括存在问题和问题解决后的版本,并指出了本地锁在分布式情况下的局限性,引出了分布式锁的概念。
SpringBoot整合Redis、以及缓存穿透、缓存雪崩、缓存击穿的理解、如何添加锁解决缓存击穿问题?分布式情况下如何添加分布式锁
|
3月前
|
NoSQL 关系型数据库 Redis
Redis6入门到实战------ 九、10. Redis_事务_锁机制_秒杀
这篇文章深入探讨了Redis事务的概念、命令使用、错误处理机制以及乐观锁和悲观锁的应用,并通过WATCH/UNWATCH命令展示了事务中的锁机制。
Redis6入门到实战------ 九、10. Redis_事务_锁机制_秒杀
|
2月前
|
监控 NoSQL 关系型数据库
9)Redis 居然也有事务
9)Redis 居然也有事务
33 0