00:00
接下来我们来编写定时关单功能,比如说当我们这个订单创建成功以后,比如们在这儿订单呢,在这儿创建成功了,当我们30分钟没有支付,那系统呢就要自动取消订单,那这个自动取消订单的流程是这样子的,那订单一创建成功,我们呢先给消息队列里边来发一个消息,说我们哪个订单创建成功了,假这个消息呢,先第一次使用这个路由件会进入到一个延时队列,等到30分钟以后,这个延时队列里边的死性又会用另外一个路由件发给我们这个交换机,交换机将这个死性呢又路由给我们这个队列来监听,它就能监听到我们将要关闭的订单,当然要关闭前订单前,我们肯定得判断他没有支付呢才能关闭,那我们这个定时关单呢,我们还是不用定时任务做来做,我们来使用这个延时队列,而且我们之前呢,在我们这个订单服务里边,把这个环境呢,都创建好了,我们也测试了这个定时关单的逻辑。
01:01
那在这一块呢,还写了一个listener来准备定时关单,那么现在呢,就来专门来写一个这个listener来完成我们的定时关单功能,点一个我们就叫order close listener,我们订单的关闭这个监听器,好它呢也是一个我们的业务逻辑组件,然后呢,我们同时让它来监听我们的详细队列,Rabbit listener,我们要监听的队列是我们之前在这测试的订单的释放这个队列,这个队列里边的所有消息,按照我们这个图示能到这个队列里边的消息都是过了30分钟以后过来的,好那么现在呢就过来,那现在来监听它,我们就直接把这个方法呢,CTRLX减过来,我放到我们这儿,要不然又来两个消费者,好现在我们把它呢就叫rabbit handler rabbit handler们来监听订单的这个消息,我们希望呢,有一个人能帮我们来进行关单,所以我们希望来调用。
02:01
用一个订单的业务逻辑,Order service order service order service and,一个autowa,那订单的这个service呢,它有一个方法叫close order关闭订单,关闭哪个订单呢?那就是这个订单,然后呢,最终关闭,但如果关闭失败了,我们还是以后使用异常机制好,我们把在这创建出来,我们来到这个订单的关闭,我们来串尝试这个关单,如果一切正常,我们就给他回复AC,那我们这个什么都是OK的,如果呢,我们业务出现异常,那们就告诉他。那我们这个消息呢,我们执行失败了,拒绝了,让他重新回到消息队列里边,我们就来写一个channel,点一个basic reject来拒绝一下这个消息,CTRLC。这个消息一拒绝以后呢,让它重新还要回到我们消息队列里边,而不能把它丢弃,所以我们来写一个true,好,瑞葵呢就写一个true,现在我们这个方法,我们就准备在这儿来进行关单,这个订单呢,我们只要创建成功就会发消息,那么先来到订单的创建这个方法来到订单的创建成功,这个订单的controller,我们是web controller来在这,我们在这呢去订单结算页,那这呢就是来创建订单的,那在下边这个订单结算页,对这是确认订单的,然后在下边我们这submit me order创建订单,创建订单呢,我们把这个I等于十除零来去掉,去掉以后呢,那它该成功,那就会成功,然后呢,我们只要成功了,我们使用rabbit term订单创建成功以后,我们就来发消息,来写一个todo订单创建成功,创建成功发送消息,发送消息给我们的MQ,那么来这个消息呢,我们就来发一。
03:51
讲来写一个消息,Rabbit tableilet好,我们把这个rabbit tempilet,我们现在再注入过来,叫rabbit tableilet,那现在呢,准备任用它来发送消息,At一个owa,好,CTRLC来复制一下,那要发的消息呢,那就在下边,只要订单我们创建完成,那接下来呢,把消息呢,我就发出去,Converter and send,那发给谁消息?
04:17
那按照我们这个队列的工作原理,那订单创建完成,给我们这个order event exchange这个交换机来发消息,所以交换机我们先来写上是我们这个交换机。好,然后呢,这一块也一样,这个交换机,然后呢,我们给这个交换机的谁来发消息,使用的路由件是什么,我们路由件呢,现在是我们这个这个order create order,那这个订单刚创建成功了,是这个路由件,然后呢,发的消息内容是什么?然后我们发消息内容呢,直接把我们创建成功的这个订单。我们呢,直接给他发出去就行了,我这个订单呢,之前会有一个保存,那在前边save了订单,我们来看一下,在这呢,我们save了一个order,那就是这个order,我们把这个order呢,直接给他一保存好这个order,这个order呢来给它在这一发出去,当消息呢发出去,这样我们这个消息队列里边呢,只要订单一创建成功,我们就会使用这个路件,路由件给我们这个交换机发送消息,消息呢先会按照我们这个路由件来到我们的延时队列,延时一定时间以后,只要过期了,它又会以另外一种路由件,这都是自动配置的,然后呢,来到我们的这个队列,然后我们就能收到我们要关闭的订单,我们呢,没有用到定时任务,好,我们现在再来启动起来。
05:36
我们把我们的这个订单和库存,我们同时都来启动起来。那么现在呢,这个订单就能创建成功了,只要我们创建成功一个订单,我们过期不支付,它就会给我们自动关掉,当我们这个关单逻辑还没写完,我们来到这个关单逻辑,我们order close listener,那既然要关闭订单,那么就在这儿来进行关单,关单呢,其实我们把这个订单的信息都给我们带来了,那就来到我们这个订单表里边看一下,想要关单,其实就是把我们指定的这个订单,然后呢,把他的这个状态一改就行了,咱改之前呢,先来查一下,因为万一我们之前呢,已经支付成功了。
06:14
因为我们来到消息队列里边的这个消息是每一个订单都过来的,但是有些订单呢,人家已经成功了,成功了你叫关单之前一定要查这个订单当前状态是什么,所以呢,这个关闭订单之前先来查询当前这个订单,这个订单的最新状态,好来查一下,那怎么查呢?我们来拿到这个订单的service,那就是当前这个service来直接调用get,把ID按照ID去来查来发送的这个订单消息,比如说之前订单创建成功。我们创建成功的时候呢,我们给他发消息的时候,直接发的是数据库保存的这个订单对象,所以呢,数据库保存的这个玩意儿,它是直接有自增ID的,所以我们直接拿到这个订单的这个ID,点一个get ID,我们就直接按照ID找,当我们也可以拿订单号找,我们找到当前的这个订单实体类,我们来先判断一下目前的状态,如果order实体类什么状态下才需要关单,那么应该是这个状态,来看一下我们订单的所有状态,Order status。
07:22
枚举我们呢,如果是待付款状态,我们就需要关单,否则其他状态人家已付款了,已发货了,更或者其他状态了,那肯定不应该关单,所以我们只有一种关单条件,就是他点一个来get一个status,如果这个status等等于我们订单,这个订单呢,现在有一个order status这个枚举点一个。他呢,现在是待付款刚创建出来的订单,如果是这种状态码,那我们就给它进行关单。那光单的逻辑我们就来进行,这个光单呢,其实就是改一个状态而已,那么就直接this点一个update。
08:02
我们来按照ID来进行更新就行,那按照ID那就是我们的这个订单实体,然后呢,这个订单实体我们要把它的这个状态更新成什么,那直接给这个实体里边保存上一个状态信息,Set status,这个status呢,那现在就是,那这个订单呢,就变成了已关闭状态,点一个cancel就是取消了,我们把这个订单呢给取消掉了,点一个get code,当然我们在这呢,给它来更新的时候,我们不应该用原生的这个实体对象,因为这个实体对象呢,我们是从消息队列里边接到的,消息队列里边这个订单信息都过了30分钟了,有可能好多属性都不一样了,所以我们呢,我们最好别用这个对象,我们应该在这关单的时候创建一个新的这个订单实体类,把ID和什么我们就封装在这里边,这就是我们要update的这个东西。好,我们这个update set status是它update点一个set ID,我们按照订单的ID去来更新的,把这个订单ID我们传过来的直接往这一放,好现在呢,我们就来写了这个关单方法,我们把这个订单服务呢重新启动一下。
09:13
我们来看一下我们能不能做到定时关单,来到我们这个定时关单,只要想要关单,我们就会收到这个订单消息,关成功了我们就给他回复,没关成功我们就给他拒绝,好我们来看一下我们现在的效果,那先来找找订单结算页,我们来重新下一个单,那先来看一下数据库,数据库里边呢,现在只有一个订单,那没问题,然后呢,包括我们这个库存工作表里边,库存工作信息呢,由于之前回滚了,这个状态呢,应该变为已解锁,但是我们呢,那个已解锁代码我们没有重新运行,我们可以把这些库存工作单都把这个删掉,我们从头到尾来测试一下,好。来测试,我们来刷新,刷新,我们现在来看一个效果,我们现在来下订单,我们来刷新,我来重新登录一下,好登录成功,我们在这儿来下订单,我们来重新下订单,那现在这个下订单呢,肯定就应该能成功来点一个提交订单,好我们发现呢,这个订单下成功,来到我们这个收银台页面了,所以来到我们的这个订单服务,我们先来看订单服务,订单服务多了一个订单28号ID,这也有,然后呢,再来到我们的库存服务,库存服务我们买的这两个商品和库存已经占好位了,占好位呢,我们库存的工作单默认状态呢也都有,这些都有,然后呢,我们接下来等订单过期,我们在这来刷新一下,因为现在呢,创建好的这个订单默认进入到订单的延时队列,这个延时队列呢,我们现在设置只有一分钟,我们测试期间只有一分钟,只要一分钟一过期,我们就会运行关单方法,而且呢,我们当时的这个订单刚创建的这个21号这个订单的状,我们来看一下这个订单创状态。
10:54
刚创建的这个订单状态status,我们来找一下default status呢,它都是零是新建状态,那只要我们一关单来看一下,好这一块呢,已经运行了,来看一下效果,来看上边的,只要我们收到我们这个订单呢,要开始来关单。
11:10
下边这一块提订单提交的数据有了,然后我们想要关单,但我们发现呢,这块订单它抛了一个异常,说listener,我们这个监听器呢,执行失败的这个异常这一块是no match,没有匹配到,没有匹配到哪个东西叫order create to,相当于我们这个to数据呢,没匹配到,那这是一个什么,说明我们在这个发消息的时候给发错了啊,我们在这儿发消息的时候。那们在这发消息的时候呢,肯定要把这个订单信息我们要发出去,这是我们这个订单信息,当然我们这个订单呢,我们来一直往上翻,我们来看一下这个order,这个order,这个order,这个order我们发现呢,它是一个order create to,那我们真正里边的这个数据,我们save order点进来,它会呢,把这个get order拿到这个实体内进行保存,所以我们要发出去的数据它不对,我们要发出去的是数据呢,是我们这个to里边的order nt,好,我们重新来到这来测试一下,好我们想要发数据,点order,点一个get order,我们把order这个实体类来发出去。
12:19
好,我们现在来重重新启动运行,特别是我们先把这个订单服务我们来停一下,因为我们现在这个消息发错了,我们这个消息呢,也没办法让人消费了,所以我们现在呢,把这个数据从队列里边呢,我们重新删上一份,把这个数据呢,我们重新移除走,好,那现在呢,这个create to就已经移除掉了,移除掉了,其实我们当时从这个to里边拿数据也能拿到,好现在把这个移除以后,那现在重新来测试。那现在这个订单服务呢,发的就是这个,我们现在重新来启动订单服务,而且呢,由于我们之前刚创建的这个订单,由于关单呢执行失败了,所以这个订单的状态默认的这个default status来看一下它的这个状态呢,肯定是我们刚新建的状态,来找一下它的这个status,好,我们CTRLF来找一下它的status,那这个status,那它现在呢,确实默认呢,都是新建状态,而且新建状态的这个订单,我们的这个库存服务一直在运行啊,这个在运行呢,我们这个订单只要没支付它呢,就会自动把我们这个库存消息解锁了,虽然你刚才那个订单有问题,我们这个库存的自动解锁,我们来看一下库存的自动解锁,我们来到库存它的这个占位,我来刷新一下,它这个占位呢,没成功,我们来看一下库存的自动解锁,相当于我们这个库存的自动解锁没有运行成功,我们来看一下他们呢,只是在这儿查出了一些信息,真正的来自动解锁呢,倒还没有运行。
13:47
来看一下这一块也没有任何的update方法啊,我们把这一块呢先去掉,那接下来做一个整体测试,订单的消息先保证它发正确,然后呢,库存里边,因为库存里边呢,默认会让他查订单的状态,订单如果是已取消状态,我们才解锁库存,但我们之前的这个订单呢,不是以取消状态,所以我们这个库存为解锁,这是正常的,好,我们现在呢,就来做一个整体测试。
14:16
我们订单服务停了,重新呢也启动起来。我们把这个消息队列里边的刚才那个废消息我们也删了,来重新下单来刷新,来,我们现在不来刷新,那重新呢,调用一个去结算方法,好,那现在来到结算确认页,是我们购物车里边的这两个商品,来重新下单,来看一下我们要下的这个订单,订单里边呢,原来两个订单,现在再来下一个订单。我们点一个提交订单。好,现在呢,这个下单成功,那现在应该有三个订单,好第三个订单,他的这个状态我们来找一下,它的这个状态为status ctrl f搜一下status,它的这个状态呢,那默认现在是零刚是新建状态,是新建状态只要一分钟以后,我们就会给他进行订单的自动解锁,我们只要没支付。
15:09
没支付呢,我们来看一下我们的订单服务,来先稍等好,我们看到我们收到了订单的过期信息,准备来关单,那我们现在呢,这个订单,最后一个订单,它的这个状态呢,就应该变成已关闭状态,来往下翻来找一下它的这个状态,那就是这个status,来刷新一下,来看一下这个status,这个status呢,应该被更新为已关闭状态,但是我们这一块呢,没有更新,那就是我们的关单方法有问题。我们来到我们的关单方法,我们在这儿判断,如果当前订单的这个状态,我们先按照订单的ID来找订单,这个订单的状态呢,是刚新建状态,新建状态我们来看一下是什么状态,那就是零待付款状态,如果是这个状态的话,那就给他关单,关单呢我们先给他设置了订单的ID,那就是我们这个ID,然后呢,还有订单的状态是这个新的状态码,然后呢,把这个订单一更新啊。
16:04
大家注意我们这一块更新的这个order entity,不对,我们应该是更新的是update,好,那现在呢,重新来启动我们这个订单服务,那么这个订单呢,由于我们这个订单没有被关单,所以我们的库存服务,即使在这儿收到库存想要解锁,由于我们订单没关单,他呢就没办法进行解锁,只有关闭了的订单。才能解锁,所以我们现在的这个库存还在这站着,那这一切正常是我们的合理流程,那先把这个订单呢重新整回来,那现在要更新的状态呢,是我们这个新的update状态,那现在再来看一下效果,我们重新再来创建一个订单,好,我们来到我们的订单服务里边。这个订单服务,我们准备来创建第四个订单。那先来刷新一下我们订单的这个结算页,To try走。好,我们现在来到订单的这个结算确认页,我们现在默认只有三个订单来提交,上一个订单走提交订单。
17:06
订单提交成功,我们消息队列里边呢,肯定会有一个订单的延迟消息,来稍等一下,这个消息队列里边确实有消息,那订单呢也提交成功了,来看数据库,订单呢,多了一个订单,这个默认状态呢,来往下拉,它是零,没问题,然后呢,再来看我们的库存,库存呢肯定已经扣减了,刚才的二变成了三,也没问题,而且我们新建的这个状单,这个订单,它的这个库存工作单的详细信息我们也有,那现在就来等订单超时,来等到order这一块超时,那原来这个库存呢是三,如果超时了以后呢,我们现在只做了一个关单,所以订单呢先得自个关闭,但是呢,由于我们库存解锁比订单慢,所以订单你只要关闭了,我们后来库存自己解锁的时候,一看你关了,那也就会关。来看一下我们订单这一块,好,现在我们收到了订单的关闭消息,我们准备关闭订单是我们30号订单没问题,来刷新一下30号订单的状态,看一下30号订单呢,现在确实变为四号状态,没问题,那接下来我们解锁库存服务,结锁库存服务呢,由于它会在再等一分钟以后收到我们库存要解锁的消息,所以们现在来等解锁库存来稍等,我们库存呢想要解锁我们这个订单,结果呢,一查看我们这个订单呢,现在已经被关闭了,那就可以解锁库存。
18:26
所以呢,他们目前是这么来联动的,我们只要呢,订单只要在这一关闭了,我们库存呢,由于它是最后一个来,所以呢,库存一看订单关了,那就可以解锁了,那在这等一下,好,我发现呢,我们现在收到库存解锁消息两个没问题,来看一下库存有没有解掉刷新,好这两个呢,重新被扣回来了,因为我们那个订单呢,没有支付,所以现在呢,目前这个逻辑就是我们定时关单的逻辑,而且我们只要订单一关,我们库存还能解锁,能解锁的原因在这儿。
19:00
由于我们这个库存呢,我们订单创建成功,创建成功以后呢,会发消息给消息队列,它一分钟以后我们会进行订单的解锁,订单呢一看没支付,它解锁了,但是呢跟订单创建成功的同时,我们也发了库存锁定,因为订单创建会调库存锁定方法,库存锁定方法呢,也发了一个库存锁定成功的消息,但是这个消息呢比订单慢,他要待两分钟,所以订单一分钟只要一关以后,那两分钟再等一分钟以后想这个订单里边所有的库存,这个又到时间了,到时间我们一解锁,再一查这个订单,诶由于我们中间有个时间差,订单呢肯定要么就关了,要么就支付成功了,那我们这个一看我们这个订单呢,已经被取消了,我们就可以放心的解锁,所以目前我们是这么联动的,但是我们说这么联动有没有问题呢?它其实有大问题,我们现在呢,假设我们订单创建成功,我们这个消息呢往出发,但由于机器卡顿。
20:01
网络慢或者等各种原因,我们订单创建成功,及时的把消息没有发出去,然后呢,我们库存因为订单创建我们调了库存方法,库存呢,它很快的把消息发出去了,然后呢,接下来导致我们这个库存的消息优先给我们到期了,所以我们这个解锁库存的这个服务收到解锁库存,他查我们这个订单支付成功了没,由于这个订单呢太慢了,机器卡顿了,或者各种原因,或者我们这个机器收到订单的解锁这个功能了,但是它由于卡了30分钟等等它都没解成功,那这个时候呢,我们去。查我们订单的状态,订单呢还是新建状态,因为我们想把它解锁,由于各种原因慢或者卡顿问题没解锁成功,所以呢,你一查,诶它呢是订单的刚新建状态,你呢就不解锁了,不解锁这个消息呢,相当于消费完了,那消费完了以后,我们把这个消息都已经消费完了,现在再也没有这个解锁订单的消息了,解锁我们这个库存的消息了,但此时你的订单服务器才反应过来,把订单的状态一改,那这就完了,我们这个订单呢,取消了,库存永远得不到释放,所以我们为了解决这个问题,我们应该这么来做,除了我们这个订单创建完了以后,我们等他自动解锁库存外,我们订单只要我们释放了,我们也应该主动的发一个消息,告诉我们这个服务,我们有一个订单释放了,所以我们订单一释放呢,我们再来发一个消息叫order release order们按照这个路由件发一个消息,告诉他我哪个订单释放了,这个消息呢,再来交给我们。
21:39
交换机,交换机呢,根据这个消息,他呢使用这个消息还有一个绑定关系,我们来给大家看一下,也就是说我们这个订单只要一释放了,发一个消息,用这个路由件,这个路由件呢,从我们这个交换机它会绑定一个队列,直接绑定到我们的库存解锁服务里边,所以呢,相当于我们订单只要释放成功了,你再主动发一个消息要解锁库存,只要此时发的消息呢,是订单信息,我们库存的消息队列里边会存两种消息,第一种是库存自己的库存工作单的消息,第二种是我们这个哪个订单给解锁了,相当于这个订单给释放了,我们把订单的消息也会直接保存到你的这个队列里边,你会收到这个消息,所以我们接下来还可以来绑定一个关系,所以我们现在来到订单服务里边,我们来到这个订单服务,我们来看一下订单服务,我们在这儿绑定关系的时候,订单服务,订单服务在这儿绑关系的时候呢,绑了一堆我们。
22:39
再来绑一个我们订单的这个交换机,订单的这个交换机呢,还直接会跟我们库存系统的这个队列来进行一个绑定,但你绑它交换机也行,交换机再路由到这儿,我们也就不这么麻烦了,我们让这个交换机跟我们这个队列再来进行一个绑定,所以我们再来创建一个绑定关系,这个绑定关系呢,它就是我们这个订单交换机订单释放,然后呢,直接和直接和库存释放进行绑定,好,我们来创建一个这个绑定关系,绑定关系的名字我们就叫order release other,这个那就叫order release other,帮定好order release other,好,Release other。
23:27
的这个帮定好,那就是这个绑定关系,那这个绑定关系它的条件是这样,首先我们要绑定的队列是谁,我们队列呢,绑定的是我们库存服务的这个库存解锁队列,我们绑定的是这个队列,好把这个队列的内容拿到这儿走,然后呢,我们队列绑定的交换机就是订单,这个交换机没问题,然后呢,我们跟这个队列绑定用的路由件是一个模糊匹配的order release other,好我们把这个呢放过来叫order release other减,那这样我们就。
24:01
整个流程变成这样,只要我们这个订单在这一解锁成功,好,我们在这儿close order,诶我们发现在这解锁了,你只要解锁成功,接下来再把我们这个订单信息再发出去,发给MQ一个,那现在使用rabbit table,我们再来convert and send convert and send,我们来发一个消息,发给哪个交换机,大家来看我们订单呢,释放成了,释放成功再给我们自己订单服务的交换机发一个消息,那就是给这个交换机。走,而且我们是立即发一个消息,不是延迟发,我们立即发一个消息,这个消息发完了以后呢,再接下来,然后呢,我们告诉他这个消息我们只要发出去,让他呢用这个路由件来进行路由,所以呢,我们的路由件是他我们要发的消息的内容,那就是整个完整的订单信息,把之前的这个订单信息直接拿过来啊直接呢把这个订单信息拿过来,那全部呢给它发出去,那发出去以后呢,就会实现这个效果,我们释放订单了,把释放的这个订单详情我们以这个路由件发出去了,但这个路由件呢,又绑定了我们库存的这个解锁队列,那这个解锁队列里边呢,我们接下来就应该来监听,所以来到我们的库存服务。
25:18
我们重新再来协调库存服务,来到库存服务那们库存服务的这个监听器,来找一下库存服务监听队列的这个监听器,好它呢会收到两种类型的消息,第一种是我们这个sto lock的to这种类型,第二种就是我们在要发出去的所有订单数据,好我们就叫handle handle我们就叫order close的,那么订单呢,关了,你订单关了呢,你也可以在这儿给我主动解一个库存,所以我们现在呢,把这个消息拿过来,CRC好复制过来,然后呢,我们收到的消息是这个订单消息,由于我们这个里边呢,没有这个订单实体类,所以我们在这发消息的时候,我们给它封装成一个to,那专门呢给。com里边再放一个订单的这个to,保存我们订单的详细信息啊,MQ。
26:12
好,接下来呢,是我们这个order to。Order to order entity order实体类里边有的,它都有一模一样的,好,我们把这个order实体类里边的属性全部复制过来,那直接呢,从这一块我们复制过来,好来CTRLC,这是我们order实体类里边的这个order to,那么以后要发消息订单呢,只要关了,然后呢,我们把这个消息对拷一下,我们使用being us。Being,点一个copy properties,把我们原来的这个订单order entity里边的数据,我们给它整到order to里边,Order to。好,我们把这个order MQ的这个to,我来准备好,把这个属性的值全部复制到这,我们给消息队列里边发它,所以消息队列里边数据的类型是它,那来到我们的库存服务,来到我们库存服务的这一块监听它呢,又能监听另外一种消息,就是我们的order to。
27:15
所以呢,我们这个库存的解锁这个队列里边,我们有两种处理,有可能呢,是我们这个库存自己过期的这个处理,也有可能是我们这个订单已经被关了的处理,你就来this out来输出一下,说我们这个订单关闭这个消息好,我就叫订单关闭,订单关闭。准备解锁库存,解锁库存好,我们想要解锁库存,那想要解锁库存怎么解锁呢?同样我们希望他有一个方法,然后呢,这个方法当然也可以是一个重载的好,除了来解我们这个库存的体,也可以来解这个订单的体,同样的我们TRY解成功了我给你返回,解失败了给你不返回,我们把这个呢拿过来在这catch exception e好,我们在这呢给他拒绝,那现在就就两种处理,我们来加上我们这种处理逻辑,CTRLC好,我们来拿过来,然后呢,我们这一块该抛的异常抛出去,好,现在是我们的这个订单的to,我们来写一个这个处理逻辑,那专门创建一个这个方法,好,这是来解锁订单,来创建出它的实现,我们就是害怕服务器卡顿的原因,订单呢,还没解锁,我们这个库存呢,判断订单没解锁,把库存锁解锁不了。
28:36
那这样呢,就造成了永久解锁不良,所以呢,现在就是防止咱们这个订单服务卡顿卡顿。导致我们这个库存,导致我们这个订单状态一直改不了,状态,这个消息呢,一直一直咱们这个改不了,改不了,一直改不了,然后呢,库存库存消息优先到期,库存消息优先到期,然后呢优先到期,结果呢查订单状态,查订单状态肯定是新建状态,新建状态,然后呢,什么都不做就走了,什么都不做就走了,所以呢,我们接下来就会导致这个,导致我们当前这个卡顿的订单,导致卡顿的这个订单,卡顿的这个订单永远无法得到解锁库存,永远不能解锁库存。
29:31
好,那现在呢,有了这个方法以后,那订单取消了,我们也给你实时发一个消息,你来解锁库存,当然解锁之前我从这个to里边,我们拿到这个订单的号,或者我们订单的ID等这个信息,我们可以先来查一下订单的状态,那解锁之前我们全部都要查这个订单状态,好来查一下这个订单状态,其实这个订单状态呢。你想要再查一遍,我们就再查一遍,你不想要查了,因为这个消息都直接发给你了,这个消息当时存的就是最新的订单状态,那我们为了把稳期间呢,我们在这儿还是查一下,查一下最新的状态,当然呢,其实不用查,因为我们来到这个方法,订单呢,就是解锁了才发消息,才能来到这个方法,所以呢,我们现在只需要在这儿来解库存,但解库存现在就问题出来了,我们现在只知道订单的订单号,我们要解这个订单怎么解呢?我们就得根据库存工作单们按照订单号找到库存工作单的ID,再来找到他之前哪些商品都已经被锁定了,而且呢,确定是我们这个商品没有被解锁过的,假设呢,这个订单都是我们这个库存服务都帮你解锁过的,你再来解锁一遍,那就造成了重复扣库存,所以呢,我们一定要查一下最新的咱们这个库存解锁状态,这才行,库存解锁状态防止咱们这个重复。
30:58
解锁库存,好,那么现在呢,就拿库存工作单来查,来导入库存工作单的这个service,库存工作单的这个service,诶那已经有了,来ctrl end,来到我们后边的这个方法,他呢先来查询我们的库存工作单,Get我们这个order task库存工作单,然后呢是八我们的order SN按照我们这个订单号来找,所以我们这个订单号呢,我交给你,然后呢,你给我找一个库存工作单,就是我们的order这个实体类order task entity,就是这个库存工作单,那主要呢,拿到他的这个task ID,这是我们这个任务,这个任务拿到了以后呢,我们根据他的ID能找到每一个商品被锁定成什么样,所以我们现在诶先来写这么一个方法,我们先按照订单找到它的库存工作单,好,我们就在这里边来,我们直接来写this,点一个。
31:58
那现在就是来一个查询库存,工作单呢,我们就来get,肯定呢只有一个,我就get one get one呢,我又传一个new,一个corry wrapper,我们现在呢是按照谁来查的,我返回的是这个工作单task,这个entity。
32:15
好,我返回的是这个工作单,我们的查询条件,查询条件呢是按照这个订单的ID,不是订单ID,是订单号,订单ID我们也没管它,好我们按照订单号,按照订单号查出这个库存工作单,然后呢,找到这个库存工作单以后,然后接下来呢,我们来给你进行返回,好返回以后呢,接下来我们就找到了这个库存工作单,然后呢,库存工作单的ID我们就知道了,那在知道以后,我们按照库存工作单的ID,库存工作单的ID那就是我们关联的这款ID,然后呢,找到你当时商品锁了几件,所以们按照库存工作单的ID找到,而且我们应该是找到所有未解锁的商品,我们才来给他进行解锁,因为我们如果已经解锁过了,就不能重复解锁,所以我们必须呢找到状态是一的这些,所以我们现在按照库存工作单,按照咱们这个工作单工作。
33:15
单找到所有没有解锁的,咱们这个库存进行解锁,来找到所有我们拿到这个库存详情的这个service点一个,我们现在要查多个,我们就来写一个list list呢我们就来写又一个corry wrapper的查询条件,查询条件呢,返回的是这个工作单的这个详情detail这个N点一个查询条件呢,就是按照库存工作单task ID我来查的,并且呢,Lock status必须等于我们指定的状态,库存工作单ID是我们这个ID,这是我们第一个条件,然后呢,第二个条件,这是第一个条件,第二个条件我们再来E口,点一个E口,E口什么条件呢,我们现在呢,必须是所有没有解锁的,我已经解锁了,就不能解了,所以lock status,好,Lock status它的这个状态呢,为几应该为。
34:13
一一呢,就是我们现在这个库存是刚新建进来的,还没有解锁,如果人家已经解锁了,这个状态呢,就会置为二,我们之前成功解锁的状态已经变为二了,好,我们现在呢,拿到所有的需要解锁的数据,然后我们再来调用我们的解锁方法,我记得我们有一个叫unlo方法,这个onlo方法呢,是这个大写的lo,好,这是我们自己定义的,它呢里边要传我们这几个数据,CTRLC,那来到我们这一块来要进行解锁的时候。Ctrl end来到我们这儿要进行解锁,它传递这几个,首先你要解的是哪个SQ的ID,你们现在呢,要解锁这么多的商品,我们就来给它进行便利,每一个呢就都来进行解锁,我们使用增强for进行便利,好每一个想要解锁,我们就来在这一块来填上信息,这个实体类点一个点一个什么呢?我们这个SQID已经有了,然后呢,再从实体类里边拿到我是哪个仓库解锁,就是这个仓库解锁,包括呢,我们现在要解锁几件,那么这一块呢,也都有这个件数,包括你当前工作单的这个详情ID,我们也都有entity,点一个get自个儿的ID,这不就行了吗?所以我们在这呢就是一个解锁,而且整个解锁呢,我们也都应该是一个事物,只要有一项解锁失败,我们整个订单呢,都算解锁失败,所以我们这一块呢,解锁方法来到这儿,我们这儿呢,只要解锁失败有异常,我们就拒绝我们这个。
35:46
订单的解锁,解锁成功了,我们就给他返回解锁成功,这就是我们来写的这个逻辑,相当于我们还有一个主动补偿,其实呢,这个主动应该是我们的主要逻辑,而我们这个被动呢,应该是一个补偿逻辑,就万一主动呢没解完,那么这个被动呢,还有一遍自动解锁功能,那么现在呢,在做一个完整的整体测试,库存服务,订单服务,我们都重新启动起来。
36:12
然后呢,订单服务,只要一创建好订单,订单呢一被解锁就会呢,立马调用我们库存服务的解锁库存,然后呢库存服务,如果这个订单先解锁了库存,然后呢在自己来解锁库存就不用解锁了,你们在这儿解锁的时候,我们会进行一个判断,我们主要呢是来判断订单状态,来在这儿进行解锁。而且呢,我们解锁的时候也判断了,如果我们这个解锁状态呢,已经被人解锁了,就不用解锁了。所以我们永远就是只要被人解锁了就不解锁了,没被人解锁,不管是运行到谁,那我们都应该解锁,而且呢,我们这个消息也不害怕他重复发多次,无论是re MQ们出现了什么故障,我们假设这个消费者消费成功了,自己断了re MQ以为没消费成功,然后呢,给我们再重发一遍,无论重发多少遍,我们这个方法呢,其实是一个幂等的,因为改不改呢,我们是根据这个状态来改的,只要状态呢改成功一次,那以后呢都变了。
37:12
那我们现在呢,来看一下它的完整逻辑,把这个库存服务先来取消掉,还有我们这个订单服务,现在来从头到尾重新来下一个订单,To try去来结算页,好,我们现在呢,如果再来下一个订单,来看我们的订单,订单呢,现在只有四个订单,包括我们这个库存的扣减,现在呢都只有两个,现在重新来下一个订单,并且不支付,好,那现在来做一个订单的提交,好,那现在呢,提交好了订单,来看一下订单有没有新增,我们点一个订单。哎,订单呢,还是四个,那说明我们那次提交失败了,可能由于远程的调用问题,提交失败了,包括我们这一块呢,也都没有啥消息,那么就来再提交一次,提交订单,好订单呢,现在提交成功,对提交成功就会来到这个页面,然后这个页面我们来看订单,订单呢多了一个,那默认他的这个状态呢,都是新建状态,来可以确认一下,好新建状态,然后呢,一分钟以后会关单,我们再来看一下我们的库存,库存呢现在都被扣了三个,我们就来等待一分钟以后的关单。
38:16
一分钟以后呢,只要一关单,这个订单一关还会主动再发消息给库存,让他解锁库存,所以一关单就解锁库存,你在这儿来测试一下。即使卡顿也没事儿,我们库存呢,最后还有这个补偿解锁,我们就来稍等一下订单的这个控制台,好,我们现在看到收到过期订单,这个已经呢要关单了,那这一块的订单状态来看一下订单的这个状态,这个状态呢,肯定已经变为几了呢,变为死好关单了,没问题,再来看库存状态走,诶库存状态呢,我发现现在已经解了,已经解了的原因就是我们订单只要一关就会给库存发消息,库存呢就会收到我们这个订单关了,我们要解锁库存,然后呢,他会拿到当时每一个解锁的这个信息,然后进行解锁,那这个呢,解锁也成功了,而且解锁成功了以后,我们呢,在这也改了,这个我这两个人已经解锁了,我就把这个状态改了,即使两分钟以后,库存的补偿解锁又进来了,因为我们这个库存呢,它只要一创建好它的延迟队列里边也有消息,两分钟以后呢,所有每一个商品。
39:24
几件我们都会到达这个队列,一到达以后呢,我们又要解锁,当我们又要解锁呢,我们会有这个判断,一判断呢,解锁过了,那就直接放过了,我们就不用解锁了,来看两分钟以后,好在这儿那们发现呢,收到库存解锁的消息,这个解锁消息呢,发现只有这些select,只有这些select并没有update,相当于没有解锁,那没有解锁的话呢,在这我们发现呢,没有重复解锁,那确定那之前锁了解了两个就是两个,因为我们在这儿改变了这个状态,那以后它想要解锁都要判断这个状态,那这就是我们利用最终一致性来进行的库存解锁,他可能没那么快,但是呢,他能允许高并发,我们订单呢,只要创建成功也好,失败也好,整个也好,我们只需要发消息就行了。
40:10
它不仅能解决高并发,而且呢也能解决我们整个系统的易购,什么叫系统的易购?比如我们这个订单呢,它是用Java写的,那这个库存呢,可能还是用PHP写的,我也无论关心怎么调PHP,我们只需要发一个消息,PHP自己感应到了,他就去来,就调用我们库存解锁就行了,这是我们整个订单与库存的解锁功能,订单自动关单,库存自动解锁。
我来说两句