07redis事务
声明:本章内容是通过学习尚硅谷_周阳老师视频以及查看官网文档总结的笔记
一.本章内容
- Redis事务的定义
- Multi、Exec、Discard
- 事务的错误处理
- 事务冲突的问题
- Redis事务三特性
- 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前任何指令都不会被执行。
- 不保证原子性:事务中如果有一条命令执行失败,其他命令仍然会执行,没有回滚
六.事务秒杀案例
- 可以在linux系统中下载ab模拟并发工具进行并发模拟。
- 在并发中会出现一些问题,超时问题,超卖问题,库存遗留问题。
- 超时问题是因为当高并发操作数据库时,并不能同时处理全部请求,当一些请求的等待时间过长时,就会出现超时问题。
- 超卖问题,是最后,库存的数量为负数。即若只设置了10个库存,但是可能存在10多个用户都显示抢到了商品,而且库存数为负数。
- 超时问题的解决方案是使用redis连接池,解决超卖问题的方案是,在业务逻辑中使用事务。
- 库存遗留问题的原因是,redis默认是乐观锁机制。并发来临之际每个请求都能拿到初始版本的数据。当一个请求完成抢购并且修改数据版本号时候,存在其他用户就不能使用该数据。
- 库存遗留问题的解决方案是使用LUA脚本语言来解决。将复杂和多步的redis操作写成一个脚本语言,一次交给redis执行,较少反复连接redis的次数,提升性能。

浙公网安备 33010602011771号