Redis中的事务、锁机制(乐观锁、悲观锁)

举报
百思不得小赵 发表于 2022/11/10 17:16:41 2022/11/10
【摘要】 **事务**,这个名词相信大家已经非常熟悉了,在关系型数据库MySQL中、对于事务的定义:**一个事务是一个完整的业务逻辑单元,不可再分。在一次事务中,多条DML语句,要么全部执行成功,要么全部执行失败**,Spring框架中提出了**声明式事务**的概念等等。可见,事务在日常的开发中是非常重要的存在。那么,Redis中是如何定义事务呢?让我们一探究竟。

在这里插入图片描述

@TOC


事务,这个名词相信大家已经非常熟悉了,在关系型数据库MySQL中、对于事务的定义:一个事务是一个完整的业务逻辑单元,不可再分。在一次事务中,多条DML语句,要么全部执行成功,要么全部执行失败,Spring框架中提出了声明式事务的概念等等。可见,事务在日常的开发中是非常重要的存在。那么,Redis中是如何定义事务呢?让我们一探究竟。

一、Redis事务概述

  • Redis事务是一个单独的隔离操作:事务中的所有命令都会序列化、按顺序地执行。事务在执行的过程中,不会被其他客户端发送来的命令请求所打断。
  • Redis事务的主要作用就是串联多个命令防止别的命令插队。
    在这里插入图片描述

Redis中进行事务操作的时候,将多个操作先进行序列化,按照每个操作顺序进行执行,如果在操作的过程中,有别的操作进行插队,那么是不允许的,别的指令不能插入到操作中,所以事务操作是相互隔离的。

二、事务操作

相关指令

  • Multi:表示开启事务。开启后输入的命令都会依次进入命令队列中,但不会立即执行。
  • Exec:将之前的命令队列中的命令依次执行。
  • Discard:组队的过程中可以通过discard来放弃组队。

在这里插入图片描述

从输入Multi命令开始,输入的命令都会依次进入命令队列中,但不会执行,直到输入Exec后,Redis会将之前的命令队列中的命令依次执行。组队的过程中可以通过discard来放弃组队。

案例操作:
进入开启Redis服务的服务器

在这里插入图片描述

从上图可以看到,三个入队的操作全部执行成功,并且按照顺序依次执行。

放弃组队:

在这里插入图片描述

错误处理

① 组队中某个命令出现了报告错误,执行时整个的所有队列都会被取消。

在这里插入图片描述
案例操作:

在这里插入图片描述

② 如果执行阶段某个命令报出了错误,则只有报错的命令不会被执行,而其他的命令都会执行,不会回滚。

在这里插入图片描述

案例操作:

在这里插入图片描述

三、锁机制解决事务冲突

事务冲突

模拟一次双十一购物的场景:

在某年的双十一期间,小王的前女友、现任女友和小王同时使用你的银行卡去抢购商品。小王自己账户总共1万元,前任女友想要给她的现任男友买一部苹果手机,于是用小王的账户花费8000元买了手机,这时小王的账户剩下2000元,然后小王的现任女友知道小王账户有一万元,于是花费5000元买了一款喜欢的包包,这时账户剩下 -3000元,最后,由于小王特别喜欢吃康师傅老坛酸菜牛肉面,于是乎花费掉1000元买了酸菜面,至此,小王的账户剩下余额 -4000元。

在这里插入图片描述

我们知道,在正常的生活场景中以上的事情是不会发生的,账户不可能所剩余额为负数,当余额不足以支付其他商品时,应该无法进行相关操作,这就是由于没有进行事务操作,出现了事务冲突的问题。那么怎样解决事务的冲突问题呢,Redis中引入锁的机制来解决。

悲观锁

悲观锁(Pessimistic Lock),就是很悲观,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会block直到它拿到锁。传统的关系型数据库里边就用到了很多这种锁机制,比如行锁,表锁等,读锁,写锁等,都是在做操作之前先上锁。

在这里插入图片描述
通俗的说:

小王账户中有10000元,小王的前女友在操作的时候,先进行上锁,上锁后其他人就无法对小王的账号进行操作,也就是说,小王的前女友买苹果手机的时候,小王的现任女友和小王对账户发起的操作请求处于阻塞状态。前任女友操作完后释放锁,账户减8000,余额2000。
小王的现任女友在买包包时,账户为2000元,进行买包操作时,先进行上锁,上锁后,小王无法进行操作处于阻塞状态,现任女友想买5000的包包发现余额不够,最终不能操作,释放锁,小王继续操作。以此类推,解决了账户最终余额为负数的问题,也就是事务冲突问题。

引起的缺点就是:效率非常低,一个请求在操作的时候,其他的请求只能等待。

乐观锁

乐观锁(Optimistic Lock),就是很乐观,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,可以使用版本号等机制。乐观锁适用于多读的应用类型,这样可以提高吞吐量。Redis就是利用这种check-and-set机制实现事务的。

在这里插入图片描述

通俗的说:

小王账户中有10000元,小王的前女友在操作的时候,先给数据加上一个字段version(版本号),例如第一次操作的时候版本号为 V1.0,小王的现任女友和小王都可以得到 V1.0版本的数据。由于小王的前女友手速非常快,先购买了苹果手机,账户减去8000元,余额2000元,此时数据库在修改数据的时候,同时修改数据对应的版本号为 V 1.1。此时,小王的现女友和小王进行购买的时候,先会去检查下当前的数据版本号与数据库中的版本号是否一致,版本号一致进行操作,不一致无法进行操作。

命令操作

①.WATCH key [key …]

在执行multi之前,先执行watch key1 [key2],可以监视一个(或多个) key ,如果在事务执行之前这个(或这些) key 被其他命令所改动,那么事务将被打断。

在这里插入图片描述

② UNWATCH

取消 WATCH 命令对所有 key 的监视。如果在执行 WATCH 命令之后,EXEC 命令或DISCARD 命令先被执行了的话,那么就不需要再执行UNWATCH 了。

在这里插入图片描述

四、Redis事务的特性

  • 单独的隔离操作
    事务中的所有命令都会序列化、按顺序地执行。事务在执行的过程中,不会被其他客户端发送来的命令请求所打断。
  • 没有隔离级别的概念
    队列中的命令没有提交之前都不会实际被执行,因为事务提交前任何指令都不会被实际执行。
  • 不保证原子性
    事务中如果有一条命令执行失败,其后的命令仍然会被执行,没有回滚 。

至此Redis中的事务、锁机制(乐观锁、悲观锁)内容就分享完啦,希望对大家有所帮助。

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。