00:00
我们继续来编写解锁功能,首先解锁之前我们必须呢,先去数据库查询一下我们库存故障单详情的信息,能看看它有没有,但实际上这个有没有呢,并不是来决定我们要解锁多少库存,那这个有没有,它能说明一个问题,就是如果我们这个库存单在我们库存系统的数据库里面有,说明我们库存是成功的,一切服务呢没有回滚,那至于下订单的其他业务成不成功我们不知道,但我们库存呢成功,如果没有的话,说明我们库存本身不成功,自己都回滚了,所以呢,如果没有,我们当然无需解锁,自己都解锁了,那如果有,如果有呢,也不能上来就解锁,因为如果有的话,只能表明我们这个库存服务自己在锁库存的时候成功了,一切成功返回出去的,但我们要看整个订单有没有成功,万一是我们整个下订单的业务,订单成了调用库存,库存也成了,然后订单掉了,其他方法,其他方法崩了,导致我们这个订单呢回滚肯定呢跟库存。
01:01
门没有啥关系,但是我们这个消息已经收到主直接解锁,那肯定有问题,我们这个订单都没有,所以呢,我们现在想要来解锁,我们在这儿证明了库存服务一切正常,想要在这儿来解锁的话,那就得看订单,所以我们能查出来,只能证明我们这个库存没问题,所以我们这块有,那就是证明,证明我们库存是锁定成功了,库存锁定成功了,但是呢,到底要不要解锁,我们这个解锁呢,还要看我们这个订单情况,如果我们这个订单现在都没有,如果我们现在就有这么几种情况,那订单呢,一是没有这个订单,没有这个订单说明我们呢,我们这个订单他呢就没有创建,我们也无须解锁,那此时呢,我们就必须解锁,因为我们这个订单呢,我库存锁成功了,确确实订单没创建,那我们呢就必须解锁,而我们的第二种情况,如果有这个订单,有这个订单,但是呢。
02:01
此时解不解锁还要看情况,我们说必须是我们这个订单呀,没人支付,我们系统把它取消了,那才有必要解锁他的库存,如果我们这个订单人家都支付了,你再去解锁库存,肯定就有问题,所以如果是有这个订单,我们呢就不是解锁库存了,我们这个不是解锁库存,解不解锁库存我们要进行一个判定,有这个订单我们要看订单状态,订单状态,订单状态呢,如果是已取消,相当于呢,我们这个系统把我们这个订单取消掉了,那我们呢就可以来解锁库存,那如果是没取消人家这个订单,无论是其他的什么状态,只要没取消,那我们就不能解锁库存,没取消那么就不能解锁,不能解锁,所以呢,我们现在是这么一个逻辑,那么接下来想要在这儿来解锁,你就来看我们的这个情况,现在有,诶,我们确实有证明我们这个库存锁定成功了,接下来我们想要解锁一定要查订单情。
03:01
情况,因为在我们返回的这个to里边,To里边呢,我们现在有一个他自己的ID,库存工作单的大ID,我们根据这个大ID呢,我们先来查出查出什么,查出我们这个真正的订单详情,那们现在这个ID得到这我们来看一下那们这个库存工作大单的这个ID,我们肯定能得到订单号,我们应该根据订单号去订单系统问一下订单系统,你的这个订单现在是啥状态,所以呢,我们现在拿到这个订单的信息,那想要怎么拿订单信息呢?我们就用order task service点一个GET8ID,我们直接按照这个ID查出我们这个工作单的信息,在这个工作单信息里边,好,我们这个test n在这个里边呢,有我们的订单号,我们点一个get order SN,然后呢,我们要根据这个订单号order SN,好,然后呢,我们接下来要根据订单号,根据订单号。
04:01
然后呢,我们查询咱们这个订单的状态,只有订单是已取消状态,我们呢才能解锁库存,咱们现在呢,希望有一个远程方法能帮我们来查订单状态,那直接来到我们这个订单的这个微服务里边,我们来写一个controller,好,订单的这个controller里边,直接到order controller来写一个方法就是呢,返回订单状态的,我就叫public r,我们就叫get order statuss,我们返回订单的状态,然后呢,我们来给他一个订单号string,咱们这个就叫order SN。然后我们就来返回订单状态,你来发一个请求叫get门,我们叫order order,我们叫status,然后呢,再来加上我们的订单号走,然后呢,我们现在来写这是一个路径变量passor来把这个订单号拿来,我们来查这个订单信息,我们直接用order service点一个get,我们要获取订单,按照这个订单号来获取,那我们就get order8,我们这个order SN,那按照订单号呢,获取这个订单的详细信息,那就直接返回订单的实体内,Order n好,我们这个订单实体内,然后呢,我们来创建出这个方法。
05:21
走这个方法呢,就是帮我们按照订单号获取订单,走打开它的实现,那直接用它的这个deo,我直接调用this点。我们get get呢,我们现在不是8ID,我们要获取一个订单,按照corry upper,按照corry wrapper查询我们的订单实体类order entity,那怎么查呢?来写一个EE口的条件就是我们的这个订单号。订单号来看一下,就是这个好,我们按照这个订单号,当然我们应该是订单系统来到订单系统里边,在这按照我们这个订单号订单号,然后呢,查出订单号就是我们这一块的,那按照这个订单号查出这个订单的详情,走,然后我们把这个订单来往回一返,Order SN来到我们这个方法,我们查到订单以后呢,我接下来直接返回return r,点一个OK,我们将查到的订单set到data里边,CTRLC,当我们现在呢,其实只想要一个订单状态,我们也可以返回订单的整个实体类,那我们这个远程方法就准备好了,那CTRLC能复制过来,接下来我们的库存服务又要调用订单,就来写一个份份的远程调用好,接下来我们来写订单服务的远程调用,Order phone servicece,订单服务的远程调用它的class好写一个interface。这是什么订单服务来。
06:48
写一个分client,我们要调用远程的订单服务,要调用的方法呢,刚才复制了直接复制过来,那复制过来我们把这个呢拿过来,好这我们要调的这个方法,然后我们来看一下我这个方法的完整路径,完整路径呢加上order order。
07:06
把这个拿过来,CTRLC,我们给我们的份这一块一放好,现在是我们的这个订单方法,订单方法有了以后,我们现在要调订单服务,一定把这个订单服务分来以说明好,然后接下来订单呢,由于会给我们返回订单实体类这个对象,那么将实体类里边的这些所有数据,那就直接一封装,封装成我们要用的这个VO来到门外库存系统里边VO那就叫订单VO来看一下这一块只是订单项的,没有我们整个完整订单的围数据,接下来就是订单的围数据。好,订单的这个数据呢,就是过来,嗯,Control home。直接给他标上一个按data方法。走,那现在我们这个订单的远程方法就写好了,来到我们这个库存服务,那想要解锁之前先来远程查订单,我们把这个订单的份我们注入过来,现在我们来注入order phone service order phone service,好订单的远程服务at一个auto。
08:13
我们现在呢,要查这个订单现在的详细信息,好,我们去订单服务,我让你给我获取一下get订单的状态,我给你传一个订单号,然后呢,他给我们返回一个R对象,那么这个R对象呢,就是订单的信息来,我们要判断,如果我们这个AR点一个get code get code呢等等零说明我们一切是成功的,这个订单数据返回成功,订单数据返回成功,那返回成功以后呢,那接下来我们就来进行消费。我们把这个订单里边的数据get data来获取出来,转成我们指定的这个type reference,这个数据好,Type reference,由于我们里边封装的这个类型。
09:03
它呢是一个我们现在指定的叫order VO,好,这个order VO封装的是这个类型,然后呢,最终从这个data里边得到我们这个订单数据,得到订单数据以后呢,我们得判断这个订单,如果是取消状态,我们才能解锁库存,如果没取消就不能解锁库存,所以我们接下来就来写一下if,如果我们来判断我们这个订单状态,它点一个get我们订单的status,我们来看一下这有一个status,如果是取消状态,取消状态呢,我们来看一下订单的这个枚举order status这个枚举类,这个枚举类呢,其实应该放在公共里边看,取消状态呢是四,那我们现在就直接来写死等等四,等等四呢,说明这个订单已经被取消了,订单已经被取消了,那取消了我们才能才能咱们这个解锁库存,好,那么接下来就来解锁库存,那怎么来解锁库存,那么这一块呢,有。
10:04
详细的这个商品在哪个仓库有几件,我们就来调用它的解锁库存方法就行了,啊假设呢,我们这呢有一个方法,比如我们就叫private。Wide我们就叫onlock,我们就叫解锁我们的库存stock,好,那要解锁呢,你得告诉我你是解锁哪个商品的SQID和他当时是是在哪个仓库扣的库存,以及我们这个扣了几件,我们现在这个配类型的数量,我们呢就来帮你来进行解锁,当然除了这个呢还不够,你得告诉我当时你的这个库存工作单的这个ID,那么就叫ID,那么就叫task detail ID,好那么接下来呢,就来解锁库存,既然订单已经取消了,就来调用这个unlockto方法,我来传入我们指定的数据,首先SQID我们来解锁,传入我们这个SQ的ID,就是在这个detail里边,好,我们先来传入SQ的ID,就是我们这个商品,那想要解锁库存,解锁上几件呢?那现在还是来到我们的这个detail里边好。
11:15
他呢,现在有一个件数,就是我们在这个仓库当时存的这个商品,然后呢,解锁几件,我们要解锁这么多件,点一个get一个SQ number,然后呢,接下来他还要我们的这个,你确定要解锁的这个工作单的这个详情ID也可以来传过来。好,然后呢,我们就在这儿来执行解锁方法,解锁方法呢,其实就是在我们的这个库存,这个SQ库存里边,把它这个数量原来呢,锁定加了,我们回过头呢,再减回去,咱们整个解锁的这个方法来写一下update来更新我们这张表,然后呢,Set set它的这个字段就是这个字段,Set这个字段。
12:02
等于它呢,原来呢锁了好多,现在我们再来减去我们指定的数量,然后条件呢,就是V,按照我们指定的SQID,我们相当于是这个商品一号商品,并且呢,它是哪个仓库的and我们的仓库ID等于我们现在比如二号仓库相当于一号仓商品在二号仓库的这个数量来解一个锁,相当于我们要调用这个方法,好我们在这呢,直接调用我们这个库存的dosq do.onlockto好,我们来解锁库存,然后呢,我们现在要调的这个方法,我们传了这几个数据,那么接下来把这几个数据直接就拿过来,SQID我们要仓库的I我们要数量呢,我们也要,那当然你的之前你自己的工作单的这个ID,哎,我们可以做一个保留字段,我们先可以不要,好,我们在这呢,就来进行解锁,来调用我们的解锁方法,来创建出我们这个方法,然后呢与参数。
13:02
很多给每一个参数呢,我们都来生成一个power来指定一下,然后我们再来生成我们的这个statementment走,那么这个statement呢,它是一个更新操作,那就来调一个更新,那么现在呢,想想要更新库存锁定的这个库存CTRLC,然后呢,我们给这一放SKU的ID,以及我们要减几个数量,我们来写一下井号大括号,数量这么多,哪个商品井号大括号就是我们这个商品,然后呢,哪个仓库井号大括号,那仓库的IDE传,那么这个解锁方法呢,你就写好了点过来,来到我们这一块,我们在这呢就调用了解锁方法,也就是说只有这种情况我们才能调用我们的解锁方法。我们查到了订单的状态,订单的状态呢是已取消,我们就解锁库存了,如果是没取消就不解锁库存了,而且呢,如果没有这个订单,假设呢,我们这个r.get data在这呢,我们想要封装它。
14:02
但是呢,他得到的东西都是空的话,那就更严重了,如果说这个data都等等,那然后我们都没有查到这个订单,如果这个data都等等那的话,那就是订单不存在,订单不存在,这个订单不存在的原因就是我们库存服务自己已经锁好库存了,库存工作单的数据呢都有,但是呢,订单掉了,其他方法把自己订单呢给搞炸了,导致订单回滚了,但是此时这种情况我们还要进行解锁,所以呢,我们应该是这样子的。如果data等等呢,Data等等呢,或者他的这个status呢,是四,我们呢,都要进行解锁库存,说明这个订单不存在,或者呢订单已被取消,这两种情况我们都要在这儿来解锁库存,好,我们这个解锁方法呢,我们就写好了,我们来测试一下,而且呢,我们在写这个方法的时候,由我们这一块呢,之前的这个消息数据来刷新一下,我们默认库存只要锁定成功,会将消息呢放给我们这个队列,但是这个队列呢,我们来重新来测试一下,好,那现在呢,这个订单服务我们得启动一下,包括我们的库存服务也得启动一下,那现在库存服务的这个service哪一块还有问题,来看一下,我们有问题的地方在这,他说这个do注入呢有问题,这个我们就不管了,直接订单服务,以及我们的库存服务,那现在呢,重新启动来测试一下自动解锁库存,因为现在写的这个库存的延时队列,这个队列呢。
15:34
默认的这个时长是两分钟,那就两分钟以后,我们这个库存只要锁定成功,两分钟以后呢,就会提交给我们这个队列,而且呢,我们专门有人去来监听这个队列,然后呢,我们监听的方法就在这rabbit handle德了,我们说了这个方法来监听监听,我们收到消息以后呢,我们就去来解锁库存。我们看一下我们整个完整的逻辑,那么完整的逻辑呢,按照我们这个图示就是这样,只要我们库存锁定成功,我们不管订单是成了还是败了,我们给消息队列里边发消息,然后呢,消息过一段时间以后,然后延迟,最终到了我们这个解锁库存的队列,我们解锁库存的服务,收到这个消息以后呢,我们就来解锁就行了。
16:16
好,我们来看一下我们的这个内容,现在我们来重新启动,好重新启动。现在我们这一块呢,重新启动以后,我们来下订单,我们先来看一下,这一块呢,有库存工作单,我们控制台这一块订单服务现在没有什么东西,我们现在又来准备下一个订单来到我们订单服务,我来刷新重新登录一下,好,现在呢,我们来重新来创建订单,那就是这个订单。那这个订单呢,我们要下单,下单呢由于是失败的,我们先点一个提交订单,订单呢创建失败了,来看一下数据库,数据库先来看一下库存,咱们这个库存呢,已经扣了有四呢变成五,但是我们单位下订单这一块呢,肯定没有新增我们新的订单数据库存呢扣了,但是我们有新添了这两个库存工作单,那这个商品在哪个仓库扣了几个,那接下来呢,想要自动解锁,等这个时间一到,好,我们这个时间呢,它只要一到,我们从延迟队列里边数据呢,只要一过去,那么就会触发自动解锁的逻辑,我们来看一下我们的自动解锁逻辑,来稍等一下这一块的时间,而且这一行的错误代码我们来看一下,走,那就是在这一行。
17:25
这相当于分自己的问题,它在这儿要远程调用的时候呢,给我们转过来行了,这个bug呢,我们一会儿先修复,当然我们先来看一个最严重的bug在这儿,我们现在呢,只要收到库存解锁服务,那想要解锁库存有远程调用的问题,我们没解锁成功,相当于我们在这儿解锁库存失败了,那如果按照正常情况,我们由于各种原因,我们解锁库存失败了,那我们肯定还要再解锁。但是我们会发现我们消息队列里边,只要我们一解锁失败,我们这个消息呢就没了,没了的原因就是我们的自动AC机制,因为现在呢,只要收到消息就会回复给消息队列消息我们收到了,无论消息处理成功还是失败,消息呢,就会从队列里边删除,所以最大的问题就在这儿,只要只要我们这个解锁库存,解锁库存库存啊,咱们这个消息失败,然后呢,我们一定要一定要咱们这个告诉服务器这个消息呢不要删,我们可以重试来解锁,一定要告诉服务器咱们这个解锁,此次解锁呢是失败的,那怎么告诉我就应该启动手动的ack机制,所以我们来到我们的这一块配置文件里边,只要是用rabbit MQ,我们在业务里边呢,一般我们都会启动手动AC开,手动AC开就是listen simple knowledge mode,这个mode呢,我们启动手动模式,这样手动模式只有我们解锁成功了。手动模式的。
18:51
的话呢,我们需要一个channel通道,好,我们来把这个通道拿来。是我们re贝塔MQ的这个通道,把这个通道拿来,只要我们在这儿解锁成功了,我们处理成功了,我们呢才能在这儿给他回复,我们这个呢,已经给你解锁了,你就来写一个basic ack,然后呢,解锁的是哪个好,我们把这个消息呢,回复给re MQ,告诉你这个东西呢,我已经解锁成功了,我们也不用批量模式啊,那现在呢,我们这种情况才能basic AC开。
19:25
那否则其他的情况如果是无需解锁,大家看无需解锁呢,说明我们也处理了,所以我给你回复一下这个情况,所以我们想要处理呢,现在就是两个环节,第一个是我们订单呢,已被取消了,订单的状态是取消或者订单不存在,我们在这呢,解锁没问题,第二个呢,是我们库存成了,但是自己回滚了我们库存工作单呢,不存在,们在这儿呢,无需解锁,我也告诉你成功了,否则其他情况我都不给你回复,或者呢,其他情况我们来看if,这呢有一个if,其他情况呢,我都给你回复,这是失败。
20:04
因为我们看远程查订单呢都失败了,我们这个消息呢,相当于就没消费,所以我们呢,在这种情况来回复一个叫basic,我们现在呢不用no a,因为这个呢是批量模式,我们现在就用这个reject,大家用下边也行,你把批量写一个false,我们basic reject就是我们的拒绝,我先来拒绝这个消息,而且拒绝了以后大家注意,我们还有一个request叫true,我们把这个消息拒绝了以后,让你重新发回队列消息拒绝以后,然后呢重新放到队列里边。这样呢,让别人再来解锁消费,让别人继续消费,继续消费解锁,继续来消费解锁。因为呢,可能我们自己机器的问题,导致我们这个解锁失败了,所以我们把这个消息呢,一定要放回队列,要不然我们队列里边这个消息一删,那就完蛋了,我们让他放回去,只有成功了,我们才让他删成功这两种情况删。
21:10
否则呢,我们就放回去,这是我们写的重构的逻辑。
我来说两句