07redis事务

声明:本章内容是通过学习尚硅谷_周阳老师视频以及查看官网文档总结的笔记

Redis官方有关事务的文档

一.本章内容

  1. Redis事务的定义
  2. Multi、Exec、Discard
  3. 事务的错误处理
  4. 事务冲突的问题
  5. Redis事务三特性
  6. Redis事务秒杀案例

一.Redis事务的定义

Redis事务是一个单独的隔离操作,事务中的所有命令都会序列化、按顺序地执行。事务在执行的过程中,不会被其他客户端发送来的命令请求打断。

Redis事务的主要作用是串联多个命令防止别的命令插队。

二.Multi、Exec、Discard三个命令

输入Multi命令后,就到达了组队阶段。组队阶段是在之后输入的命令就像进入了一个队列中,但是这时并未执行这些命令,直到输入Exec命令后,Redis就会顺序执行队列中的命令。在组队的过程中可以通过Discard命令来放弃组队。

所以事务使用的顺序为: multi->其他命令->discard(使用可选)->exec

 三.事务的错误处理

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

在执行阶段中某个命令出现了报告错误,则只有报错的命令不会执行,其他命令都执行。

 例子:

在组队阶段出现异常:

 

 在执行阶段出现异常:

 

 

 四.事务冲突问题

场景:若0号库中,存在一条记录 key=money,value=1000

若同时打开三个客户端,第一个要让money-800,第二个要让money-500,第三个要让money-100。并且这三个客户端同时执行了该条命令。那么结果是,value值变为了-400。那么三个客户端都会感到疑惑,为啥value变为了-400了呢?

 那么这个问题该怎么解决呢:

在Redis中针对上述问题有两种解决方案(其实也可以是一种就是上锁的机制)

悲观锁:三个客户端同时执行命令,但是真正执行的时候肯定还是有顺序之分的。第一个执行的客户端对money进行操作时,就会对money进行上锁。上锁后其他客户端就无法对该money进行操作了,并进入阻塞状态。除非第一个执行的客户端完成操作并释放锁。

悲观锁。顾名思义,每次操作数据的时候(操作要么读要么写)都会认为会修改数据,所以每次操作数据都会上锁,这样别人想操作这个数据就会阻塞,直到它拿到锁。传统的关系型数据库里面就用到了很多这种锁机制,比如行锁,表锁等,读锁,写锁等。都是在操作之前上锁。但是这种锁的效率极低,每次只能一个客户端进行操作。

乐观锁:三个客户端同时执行命令,并且同时拿到相同的初始版本的数据。在底层执行过程中还是会存在执行的先后顺序的。那么当一个客户端先执行操作,并修改了内容后,就会更改money的版本号,接下来当第二个客户端操作数据时候,会先进行版本号的判断。若版本号不一致,那么就会重新拿当前版本的money再来进行操作。当钱不够能情况发生时,就不会进行操作,更不会出现value出现负数的情况了。

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

 

乐观锁和事务特性

 WATCH key [key...]

在执行multi开启事务之前,先执行watch key.... 对一个或多个key进行监视,如果在事务执行之前这些个Key被其他命令所修改,那么事务就会被打断。

演示:

 

第一个客户端:

 

第二个客户端:

 

 这里就是使用的乐观锁,当第一个客户端执行完成后,修改了money,money的版本号也发生了改变。当第二个客户端执行事务时候,发现money的版本号发生改变,就执行失败。

 UNWATCH 命令是取消对某个key的监视

 

五.Redis事务的三特性

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

六.事务秒杀案例

  1.  可以在linux系统中下载ab模拟并发工具进行并发模拟。
  2. 在并发中会出现一些问题,超时问题,超卖问题,库存遗留问题。
  3. 超时问题是因为当高并发操作数据库时,并不能同时处理全部请求,当一些请求的等待时间过长时,就会出现超时问题。
  4. 超卖问题,是最后,库存的数量为负数。即若只设置了10个库存,但是可能存在10多个用户都显示抢到了商品,而且库存数为负数。
  5. 超时问题的解决方案是使用redis连接池,解决超卖问题的方案是,在业务逻辑中使用事务。
  6. 库存遗留问题的原因是,redis默认是乐观锁机制。并发来临之际每个请求都能拿到初始版本的数据。当一个请求完成抢购并且修改数据版本号时候,存在其他用户就不能使用该数据。
  7. 库存遗留问题的解决方案是使用LUA脚本语言来解决。将复杂和多步的redis操作写成一个脚本语言,一次交给redis执行,较少反复连接redis的次数,提升性能。

 

 

 

 

posted @ 2021-07-18 18:33  Costin  阅读(71)  评论(0)    收藏  举报