00:00
前面呢,我们讲了一个社会语句更新库存,它可以实现,它可以解决我们的闭环问题。那么但是呢,它有很大的局限性啊,比如说呢,同一个商品有多条库存记录的时候,那我减哪条库存记录呢。啊,搞不清楚了。那么另外第三个问题呢,就无法记录库存变化前后的状态。那那么这个呢就比较麻烦了,因为它是一个SQL语句,变化之前多少件库存,变化之后是多少点库存,他是完全不知道的。好,那我们就可以呢,使用行呢,使用悲观锁,那悲观锁呀,就可以解决这两大问题。那么咱可以先进行查询,并且呢锁定库存,然后我们再去判断更新库存。那么就可以回到一开始的这种玩法了哈,那么在查询的时候先去呃锁定库存,然后来进行判断。判断完了来去更新,更新完了最后呢,去解锁,那有点类似于咱们这一块。
01:04
那只是呢,咱在SQ语句里面,那就完成了。那我们要借助于select for update。那么对于这个东西啊,有些同学呢,可能比较了解了,那也有同学呢,可能不太了解,那没关系,我们来给演示一下,那我们来使用这个客户端演示一下。那么首先呢,我这里有两个连接,一个是一,一个是二。那么在一这个里面,我先去开启,开启一个事物,开启事物之后啊,那我们要去扣减库存之前,肯定要去查询库存列表。比如说我根据1001这个商品编号来查询它的库存列表,应该有这两个。那么将来呢,我再根据各种分析啊,比如说有各种大数据的一些框架,它可以呢,分析我从哪个仓库去发货。比如说我在北京,通常情况下可能是北京仓那里发货,但是呢也不一定,比如说北京仓无货的情况下,可能需要调配。
02:06
那么大数据呢,有这种分析流框架啊。那我们这个先不管,我要去先查询出有哪些仓库,有哪些库存满足我们的要求。咱肯定要来一个什呢,来一个select from DB talk。那么围绕条件呢?是product code等于1001,好,我们回车。那么此时我查询出有两个仓库,或者说有两条库存满足我们的要求。那我这里的话呢,如果不立马把库存锁住的话。可能其他人呢,都来买了。哎,把库存呢,减完了,减完之后,但是我当前这个用户不知道啊,我依然认为呢,有两条仓库都满足要求,那可能就得减某条库存了啊,就减了。那么此时就会出问题。
03:01
那你比如说呢,如果你不锁住的话,那么这是另外一个用户。他可能有很多其他用户都已减库存去了,那他也写一下吧,来一个update dbto set count等于countt减一,那么VR,比如说咱就减第一条库存VID等于一,哎,减了。那么接下来之后下来看啊,我的酷丙乙烯还剩多少件呢?4998件减完一点库存了,但是用户1亿呢,他感受到了吗?没有感受到,他依然认为呢,库存还有4999天了。它会在这个数量的基础上A减固存。那必然会出现这种并发性的问题。那怎么解决这个问题呢?但差别呢,不能这样一插。我们要适合呢,使用select for update。那在最后这个位置,我们添加一个up for update就可以了。来我们呢,查询的时候呀,要加一个for update,那么此时我们的库存应该已经查询到了。
04:06
4998件。并且立马把这两条记录呢也给锁住了啊。如果你这个时候。来一减库存的话,比如说其他用户,哎,这个用户又来捣乱了。来减库存,那么能减成功吗?减不成功这一次呢?被阻塞在这里。直到我第一个用户减完库存,失误提交了或者回滚了所释放掉了,那我这个位置呢,其他用户才能去减库存。好,那我们来去看一下,比如说呢,大家出出问题了对吧,回本了,或者说他剪完了,剪完之后呢,已经提交了。或者回滚,那么此时事务结束,你看我这边这个用户呀,才能去扣减库存啊。哎,那么使用for update是可以锁住的。那么它锁的话呢,哎,那么它是锁。一个仓库呢?
05:00
还有锁魔界仓库的。它的范围啊,就取决于咱们的被关锁的这样的一个条件。啊,由于呢,我们的protect code已经创建索引了。并且我的条件呢,也是一个具体值,所以它应该只锁上呢,只锁这两条记录啊,它是一个行极所。如果此时你去更新其他库存记录的话,是不影响的。那所以呢,咱这种写法呀。没什么问题啊。那么回到代码里面去。我们看代码该如何去实现它。那么首先呢,咱们还是回到这个service里面去啊,我们要在service里面来改造。那我可以呢,把这个方法呀,来拷贝一下。然后呢,放在这个上面去啊,因为在这个本地所呀,我们也不用去演示了,那么这个地方呢,咱给它改成一个二。那咱调用的是达这个方法。那么这个方法呢,我们可以给它还原一下啊,全部给它删掉就可以了。其实。
06:04
咱就在这个里面来实现。那么实现过程呢,跟最初的实现是一样的,首先第一步我们要去查询查询库存信息。查询完了要立马给它锁住,让并锁定库存信息,好那么然后呢,第二步我们要去判断库存是否充足,好那么然后第三步呢,咱们这里开始去扣减,扣减库存。好,那么每一步他应该怎么去完成呢?那第一步。我们肯定要通过咱们的这个CQ语句,那么来去完成。那么这个SQL语句啊,咱们肯定要去写circle了啊。那我要去定义,需要去自定义map方法。那我们来一个,来一个查库存的方法。
07:00
那返回结果集肯定是一个例子的集合,然后呢,是一个库存集合。他把这个list给它导入进来,导入好之后呢,咱们的方法名来用query talk,那里面的参数咱先不管它,那我们的SQ语句应该是色类的标签啊,这个里面的SQ语句啊,咱对应的应该是这个SQ语句,咱给它拷贝过来,让它放在啊这个里面去。那放进之后呢,我们来看有些参数咱就要动态的传递进去,比如说呢,商品编号。那我们这在它替换成替换成井号发括号啊,Doctor code啊这个玩意。那我们得要有这个参数呀,于是呢,我们在方法行参里面要定义一个口罩factor code,但这个参数名呢,由于只有一个参数,所以这个位置呢,是任意参数名都可以接受。
08:01
但你也可以指定参照名,通过it派上注解。那我这里呢,就不带指定了啊啊这样呢是可以检测到的。那么然后呢,我们来看啊,咱第一步呀,我们就可以去完成了啊,我就可以调刚才咱们这样的一个方法。来在这里的话呢,那就可以来一个this.this.stock map点上talk。好,我就传一个1001这个商品编号,最终返回的是一个库存列表。那么这个库存列表,我从哪个库存里面来减呢?从哪个库存里面来讲的,那咱肯定要去根据一些大数据分析。来看哪一个仓库呢比较合适,效益比较高,离得比较近。来,去发货。那我们现在的话呢,比如说咱就取第一个。库存我又取第一个,我们也没什么分析了,对吧?啊,也无法去调配了,咱就从第一个仓库来接,那么实际开发中呢,这个呢,是需要很复杂的一些判断的啊。
09:07
那么咱这里呢,就全部略过,因为咱的目的呢,不是讲这个减库存这个业务啊,而是为了讲所。那么这里啊,这里我就取第一个仓库,第一个库存,那么来进行扣减。啊,这个位置啊,来一个tos减上GET0。然后呢,我们的反对结果啊是to。当然呢,这个地方你最好是判空一下,如果这个集合为空了,那么咱就出就出现控制异常了。那这呢,我也就略过了哈,因为我可以确保这个商品编号对应的库存不为空。那么然后呢,咱第二步这个位置,我们要去判断你最终过拿到了这个库存,这个库存对象是不是为空,若为空了的话。
10:01
那咱就不用减库存了呀,因为没有库存,没有仓库,没有库存满足我们的要求。那咱要扣减的就不用扣减了。好,那么如果他不为空,说明有仓库满足我们的要求,给我们返回了一个最合适的仓库给我们了,那其实就是第一个对吧?啊,其实我们这就第一个啊,然后stock如果不等于,那要并且stock点上get count要大于我们的购买数量。那我们这里是哪一件,所以呢,要大于。大于等于一就可以了,对吧,或者大于零就行了。那我们在这里呢,就可以进入第三波了,来去扣减库存。那么扣减库存呢?咱们的四库语句。哎,我们也可以去写一下,或者呢,我们就使用通用来提供的就可以了,那来一个stop,点上set count。然后呢,是stock点上get count减一键嘛,然后给它保存进去。
11:05
this.stock map点上update by ID,把这个stock给它放进去。好,那我们就完成扣减库存这个动作了。那最后呢,事物结束,事物结束,那么咱的锁也就释放掉了。这如果我们要使用方法不带数的话,那这个地方呢,咱尽量使用手动实物啊。手动15。来来,加个15度点。好,那么咱这样呢,学好之后,那么好不好用呢,我们得要去试一下。那么又重启这两个符,先重启第一个,然后再来又重启啊。第二个服。那么两个服务的重启啊,应该问题不大啊,我们可以看一下都没什么问题,都启动成功了,那么启动成功之后呢,我们再看到这个库存里面,现在是4997件。我现在浏览器中呢,去访问一下啊,来去刷。
12:02
嗯,刷我多刷几下啊。来看一下最终库存数量。每访问一次,它会减一。还剩4993件。那么库存数量重新改回5000件库存,那我们去保存,那保存好之后啊,咱们使用压力测试工具,我们去压一下,把这个呢给它清空掉。啊,清空掉之后呢,我们来去运行,看这种效果怎么样。那吞吐量呢,明显受到了很大影响。那悲观所呢,其实性能呢。不是那么高啊,特别是在我们手动事物的情况下。OK,还有600左右的吞吐量。啊,比gbm呢,好像稍微好一点,但是比我们一个SQL语句的时候呢,性能要差很多啊,因为我们所的力度。锁的力度然后变大了,之前我只锁,只是一个更新语句的一个锁库存。那么现在呢?
13:00
我们是多条SQL语句。那么他要反复的跟ma狗类交互,那必然会导致性能下降。好,那我们来看最终库存数量是不是零呢?啊就是零。啊,这就是零啊。那说明咱们闭关所也可以解决啊,我们的并发性的问题。
我来说两句