00:00
做机制是要第二种情况,就是我们的事物就是事物。如果我们减库存操作,往往呢不是独立存在的,我们可能会配合订单和支付。那比如说呢,我们可能下订单的时候可以减库存,也可能会在支付的时候呢,可以减库存。那不管是哪种情况,我们要通过事物可以保证咱们操作的原子性。啊,保证呢,咱们操作呢,要成功都成功,要失败都失败。那么再有失误的情况下,咱们的所机制呢,就有可能会失效,那我们来演示一下。那么首先呢,咱把这个多立模式呢,给它处理掉,然后在我们的方法上可以加上事物注解。那么加上之后呢,我们来去重新启动我们的服务,那就直接去演示这个问题哈。好,重启呢,应该是问题不大,应该只是加了一个注解而已嘛,已经启动成功了。然后再找到这个数据库,把库存数量改成5000,改好之后呢,找到压力测试工具。
01:00
好,我们来去把这个东西呢清空,我们来去运行压力测试。此时咱们的吞吐量比有锁的情况下,比存锁的情况下性能要高一点。比五锁或者多利模式呢,性能要低一点。然后5000个请求都发送完成了,并且都已经成功了啊。那么的库存数量有没有减成零呢?我们去刷新一下,再看还剩21件库存。明显没有减为理由。那说明说明还能说明所基制又失效了。虽然这个概率呢比较低,但是还是有可能的啊。好,那我们来去看一下,为什么导致所机制失效了呢?那么你要理解为什么所依的失效,一定要搞清楚事物加入之后,在方法执行的流程变成什么样子了。那么当一个请求到达我这个减库存方法的时候,那么咱们会怎么样?由于呢,我们有这个事物注解啊,事物注解我们都知道,它通过AP的思想,那么来去赋能的啊和赋能的。
02:07
那么它会在A的前置方法里面先去开启事物啊,就在方法之前,那么开启事物。那么然后呢,进入我们的方法啊,开始去获取锁,所以第一步呢,先去开启事物,然后再进入我的方法呢,获取锁啊,那么我可能使用这个lock更加理解,更加好理解一点,咱可以呢,把这个东西呢。给它解开啊,把这个呢也给它解开。啊,把它格式化一下。啊,这个呢,更好理解一点哈。那我们一个请求过来了,他首先呢,会去开启我们的事物,这是第一步开启事物,那第二步呢,开始去获取锁。第三步呢,开始去查询库存,那第四步呢,开始去更新库存啊,那么然后第五步呢,开始去释放。释放所,那么第六步方法执行完了,咱们应该是提交或者是回本事务啊。
03:04
或者是回滚15。那么单单个请求的情况下,流程这样子的,那么如果在并发情况下会怎么样呢?好,咱可以呢,通过一张图表来去梳理一下啊。那咱可以呢,在这个里面呢,加一张主表啊,我这里的话呢,稍微多一点啊。那我就来一个啊,这样的一个图标。把这个呢,给它变得宽一点,因为我要写文字在里面啊。假如呢,我这里呢,有两个用户同时发送请求过来了,一个是A用户,那么还有一个呢,是。B用户啊,B用户,那么这两个请求啊,这两个用户发送请求同时到达,我们的抵达的方法来预减库存,那么他们呢,都会怎么样,都会开启一个事物。所以呢,此时呀,我们会开启两个事物,来一个比根。当然啊,这个K也是五。好,这的话呢,它是比根开启事物啊开启事物,那么然后这个后面啊也是一样,那么B用户啊,它也会比根开启事物,对照代码来解释一下,此时呢,有两个用户,一个是A用户,一个是B用户。
04:13
在进入方法之前,他们同时开启了一个事物。此时呢,进入方法内部,进入方法内部两个请求同时去获取锁。那么只有一个请求呢?可以获取所成功。那假如说呢,A方法运气比较好,他先获取所成功了,于是呢开始去先查询库存。那么然后再去更新库存,更新完了之后呢,要去释放所,最后呢来去提交事物啊。那A用户呢?获取到锁之后,他就可以去查询库存了。那我们在这个表格里面,那么假如说A用户获取所成功,那B用户怎么办呢?B用户的请求啊,只能在锁之前阻塞着。
05:01
那么A获取锁成功之后,他开始去查询库存,那么执行我们这行代码查询库存。那么这是查询库存,假如说此时查询的库存数量,那么是21件,那么显示的是21件库存啊。那么21件库存是符合我们这样的一个要求的。所以他就会啊,减库存了,对吧,但是去扣减库存。那么这个位置呢,紧接着他就开始去。扣减库存,库存量呢,就变成20了。那变成20之后,他开始去释放我们的所在方法执行,执行完成之前。要去释放我们的锁,那此时呢,开始去释放锁,那么释放完锁之后呀,那方法呢,就执行完成了。那最终呢,开始去提交事务。那么假如说呢,事物还没来得及提交呢。
06:01
那B用户是立马获取到锁里的啊,获取到这个锁了。OK,那么此时我还没来得及提交呢,那么于是呢,B用户呀,他开始立马获取所成功啊,获取所成功,那获得成功之后。那开始非常巧,他应该立马查询库存去了。那么此时查询库存,查询库存,他查了多少件库存呢?注意啊,咱A用户的请求还没有提交呢。B、用户查询库存。查了多少件了?查的是21件库存。如果你不信,我们打开doc窗口,我们连上MYSQL数据库,杠u root,杠p root,咱们通过命令行的形式来演示一下。那我这呢,已经连上MYSQL数据库了,那么另外一个我们也再开几个链接啊,也连上MYSQ数据库,一个颜色A用户,一个颜色B用户。
07:04
那么啊,咱这里呢,是不是我们的MYSQL服务器呢,我们可以查看一下数据库啊秀data那大可以看到有分布式锁这个数据库,那说明应该就知道了。那我们来去使用这个数据库,把它给放进去,把它给使用了,把数据数据库呢切换成功啊。那么然后另外一个我们也要去使用分布式锁这个数据库。好,也切换过来了,那么它有哪张表呢?来一个show tables,咱可以看到里面有一个DB talk这张表。那我们两个用户。进来之后同时开启事物啊,那么我们这的话呢,有两个用户,一个是A用户,那么开启事务,那B用户呢,也来开启事物,来一个begin开启事务。看见事物之后呢?A用户先获取锁成功了。他开始去执行查询库存的这个操作。
08:02
那么查询库存本质是根据商品编号来查询的啊?那么对应的C语句应该是A,用户获取锁成功之后啊,开始执行select,听from from DB talk where pro code等于1001,这个用这个商品编号,你没回车查询到库存了。那么查询到库点之后呢,他开始去判断,判断完了开始减移,减移完之后呢,更新到数据库。所以呢,扣减库存在我的MYSQL里面本质就执行了一个update操作,根据ID可以更新库存数量。那么呢,思QL语句应该这样子的,来个update DB talk,然后set count等于20,在你查询到库存的基础上,诶,减一过之后呢,更新进去。那么条件应该是ID等于一,根据ID的一根线。
09:03
那么一回车就可以好了。更新好之后呢,紧接着我们来开始释放锁。释放锁完了B用户此时呢,就可以获取到锁了。那么可能A用户呢,还没来得及提交呢。B用户呢?先查询库存来了。那B用户呢,此时呢,诶,他依然获取到锁,执行查询口令操作去了。那查询方式呢,跟A用户是一样的呀。同一个代码,同一个参数,那么开始去把这个词口语句呢。咨询一下,查询库存。40差应该是多少呢?21。因为MYSQL的默认隔离级别,它可能是I2跟那个瑞。Repeat包,Repeat包,然后是read这样的一个玩意啊。I是可重复读。不管是可重复读,还是读已提交啊,还是这个读已提交,那么他们呢,都是只能读提交后的数据。
10:02
而此时A用户呢,更新好了,那他提交了吗。没有提没有提交啊,没有提交的情况下,那B用户能不到这个20吗?都记不到这个20。他只能读取到最近的一个提交数据,那就是21了。那么对了之后呢,那么他开始紧接着啊,紧接着A用户提交去了,那此时他就提交去了,那此时他提交提交事物,那对B事物来说还有影响吗。没有影响了。因为A的话呢,已经读取到了啊,读取到这个库存呢是21。紧接着开始判断,然后检移过之后呢,保存到数据库。紧接着开始判断检一过之后的保定数据库啊,扣减库存,它是在21的基础上扣减库存的。那库仑分量多少呢?20。然后呢,开始去。开始去释放释放所对吧,释放所然后呢,提交事物,提交事物。
11:08
那最终结果怎么样呢?两个用户同时发送了请求,都买一件商品,结果呢,库存只减了一个。应该讲几个呀。两个用户应该减两个呀,那最终只减了一个。那我们来看一下这个最终效果吧啊。那B用户读完了,A用户呢,想起来提交了,那回到这个A用户里面去,他此时呢进行提交了,但是B用户呢,都已经读就好了呀,依然是21件。它只会在二十一键的基础上减一过之后,然后更新到数据库,Update DB talk,然后set count等于20VID等于一这样子。那咱最后呢,也要去释放所提交。那么在数据库里面最终数量还是20件。只减了一个一个库存。
12:00
那不就出现超卖现象了吗?好,这就是咱们这个事物导致所机制失效的一个原因啊,就是在这方面。就算在这个位置,因为咱的数据库的隔离级别,一般呢,我们会设置为IC和这个RR啊这样的隔离级别。读一体胶或者可重复读。因为呢,在一个事物只能读取到另外一个事物已提交的数据啊。哎,那么来想一想啊,如果我一个事物可以读取到另外一个事物未提交的数据。未提数据不是20吗?那不就解决这个问题了吗?哎,这个想法呢,确实有道理。如果我们在这个事物里面来设置下隔离级别,那默认呢,是取决于数据库的隔离级别啊,在MY默认隔离级别呢是。可重复读哈,可重复读,那隔离级别太高了。哎,如果把它设置一下来一个S。那么有一个枚举类默认情况下可以看一下啊,你可看一下你默认隔离级别呢,是它是不是这个,那这个隔离级别呢,就取决你的数据库的隔离级别了。
13:06
那么MY呢,是可重复读。那我们呢,就可以设置为读未提交。好,那么来设置为独尾交看一下啊,来一个isol,然read on committee的独尾提交,那能不能解决咱的超麦现象呢?好,我们来去重重新启动一下啊。重启好之后呢,我们再把这个库存数量改回这个5000这个库存数量,那么改好之后呢,我们找到压力测试工具,我们再去压一下啊,把这个呢给它清空。好来去启动单元测这个压力测试。啊,启动的话呢,性能啊跟前面差不多啊。那最终效果怎么样?5000个请求全部发送成功了。那么这个库存数量来我们来刷一下来看,减为零了。那么也就是说,如果我使用毒未提交的话,就可以解决这种超慢现象了。
14:04
但是。咱在订单或者支付里面。能给它设置为独立题吗?肯定不能,咱一般的都是使用它呢,是用读乙体调或者读胃体调。他们呢,都有可能会产生我们的超卖现象。然后这个地方啊,事物啊,事物这一块啊,也可能会使咱们这个所失效。那你使用这个read,然后呢,On committee。Uncom的,那么可以解决这样的一个问题,但是呢,咱不能这样去用啊。
我来说两句