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中的事务、锁机制(乐观锁、悲观锁)内容就分享完啦,希望对大家有所帮助。
- 点赞
- 收藏
- 关注作者
评论(0)