00:00
那呃,前面我们在这个代码当中呢,就是分析流程的时候呢,分析了一个叫做接口调用文明的性原则,我们再在这里面总结性的去说一下,到底什么叫做结果叫能明等性,那么它就是用户对同一操作发起的一次请求或多次请求的结果应该是一致的,这种呢,就是我们的这个接口满足了密的一些原则啊,然后不会因为多次调用而产生了一些副作用,那这样的话呢,我们呃,其实是一个密转性接口啊,那最简单的例子就是咱们说的这个支付了,包括就是刚才咱们那个充值的部分,也包括未来你们比如说电商里面做的这个支付,那它其实都是需要做这个密存性的啊,然后呢,呃,这个支付其实就是这样的,比如说我们在这面啊,是我们的,呃,比如说是电商的商城平台,然后这面呢,是我们要的那个支付。
01:00
宝的支付接口对吧?啊,你在商城平台里呢,呃,去发起支付的时候,那它应该去连接支付宝对吧?啊,然后连接支付宝之后,比如说嗯,你这个,比如说你的这个商城平台里面,它也有这个余额的设置啊,也有余额的设置,然后呢,你连接完支付宝之后呢,支付宝这面扣完款之后,他支付宝这边扣款,然后你商城这边呢,他会通知你,就是那边扣款成功,如果有余额的话,也要改余额,如果没有余额的话,他至少要通知你这边扣款程度是这样的事情吧?啊所以呢,这个是整个的一个正常的一个调用的流程,那他怎么通知你,他是不是会发送一个回调请求啊,明白吧,就是你连支付宝去做扣款,扣款了之后呢,你在你连支付宝的过程当中呢,会携带一个参数过去啊,携带参数过去,这个参数是什么,就是你告诉他回调地址是什么,跟咱们现在的这个充值是一样的,然后支付宝。
02:00
这边呢,他拿到你的回调地址之后,他这边如果扣款成功了,他会调用你的这个回调地址来通知你,我这边扣款成功了,如果你这边也是有那种充值,就是有一些平台上他是先需要充值的,对吧?啊,如果你这边也是有充值需求的话,那他这边呢,也会把这个钱呢给你扣下去,就你支付完了之后,他会把钱给你扣下去,对吧?嗯,然后你这边扣钱也好,得到通知也好,修改还要做什么,是不是修改订单状态呀,你订单状态是不是就是应该是一个已支付的状态啊,好,所以所有这些都是应该我们在回调的时候说的,回调做完了之后,我们是不是应该向支付宝去响应数据啊,就是一个请求一个响应了,响应的时候,我们就应该告诉支付宝说我这边已经处理完了,处理什么,处理完了,处理我的订单状态,处理完了,处理我的这个余额,处理完了好,那支付宝这边接收到了你的小名之后,他还会不会给你再次的发起回调通知了?
03:00
就不会了,就不会了,那假设说跟刚才我的情况一样,我已经处理完了,我给支付宝发送响铃的时候,支付宝突然断掉了,那么支付宝是不是没有接收到咱们的这个回调响应啊,他没有接收到回调响应,支付宝也会有重试的这样的一个机制,他就会给我们发起重试,那重试的过程当中。那么他是不是就再次的修改订单状态对吧?好,那这个倒没有什么关系,因为这修改了两次嘛,从修改订单状态就是从呃未支付到未支付对吧?但是如果你这边有这个余额的话,那么他是不是又扣减励金额,那你是是不是就相当于你支付一次扣了两块钱,我买了一个十块钱的商品,扣了20块钱啊,如果我们给他响应的时候呢,又发生了这个呃连接的问题,没有去连接上,那么支付宝还是没有收到我们成功的小将啊处理成功的小呢,支付宝又给我们发起个回邀进去,然后呢,又扣了我25块钱啊十块钱明白这个意思吧,所以那就反复的扣钱,这个就不是你反复充值了,这就反复扣钱了,你会发现你买了一个商品花了好多次钱,那取决于他回调了几次,所以说这个也是有这种啊,就是密等性的这个问题啊,啊都有等性的问题,凡是回调都有等,凡是这种回调我们都要去解决这个。
04:25
密等性的这个问题,然后你要去详细的分析一下这个密等性,它会出现在什么样的一个场景下,然后这种场景下出现了的话,我们要怎么去解决这个问题,所以刚才我说的是支付宝的这个问题。是不是判断订单状态。刚才咱不都说了吗,你订单状态这面不就改了吗?改了之后订单状态每次回来它都是它默认它就是敏德性的,你不处理它都是敏德性的,因为你支付完了之后,他的订单状态就是改成成功,所以你这边判断一下,如果订单状态已经是成功了,那还改啥呀,都成功过了,你不能再成功一次了,你再成功一次就是第二次扣款了,对不对?所以说其实这个业务流程大家只要只要是仔细分析的话,从中你肯定能找到一个突破点啊,但然不同的商城,它可能它的一个具体的数理机制也是不一样的,你说刚才我们说的这个是我们在这个商城里面可能是有余额充值对吧,但是现在呃,可能就绝大部分商城它是没有余额的,它是直接是支付宝,就是三方支付的对吧?啊,就是三方支付三方管理账号,那这样的话呢,可能他问题呢,还有一些其他的问题啊,所以每一个系统其实都会有每个系统它特定的一些问题,然后到时候咱们具体问题具体分析好,那这块呢,是我们。
05:46
一个接头叫幂等性原子,然后呢,接下来呢,就是呃。刚才前面咱们提到过的就是它之所以啊要解决这个密警性,就是因为回调这块一般情况下都会有出示,为啥它就防止网络,因为毕竟是一个远程访问嘛,远程访问难免会有这个远程网络连接失败的情况,那么我们说一下另一种情况,就是比如说我这面还是刚才我说的这个。
06:17
呃,就是商城这个问题啊,我这边发起了一个下订单对吧,下订单完了之后不就扣款吗,扣款之后我支付宝这边不就把款划走了吗?发走了之后好,他给我响应的时候。网断了,就这时候就还没收着呢,断了。如果他没有从事集就会怎么样?对,你把钱已经支付了,你会发现订单状态没改,还是未支付,你支付完了之后,你半天你他我支付了呀,这订单状态怎么还没支付呀,这个就是他当这年回调没有重试机制的时候,就会出现那个问题,明白吧,这个时候你可能就得打客服,你我这个钱已经支付了,然后订单专都没改,然后客服专都给你查一下,行,你这样的话,你就无形当中就增加运营成本了,对不对,所以那我们在代码层面就直接给他来个重试,那不就解决了这个问题嘛,一次不行两两次,两次不行三次,总之我们有一个重试,重试机制吧,对不对,就是解决那种那个暂暂短,就是那个短暂性的这个网络连接失败的这种问题,这种短暂性的网络连接失败东西还是经常会出现的,对吧?啊,所以说解决这个问题啊,所以这是从事频的由来,以及从事的过程当中可能引发的密等性的问题啊,所以这个大家要知道。
07:40
那这块呢,就是对会付宝当中那个重试的那个代码啊,就把它放在这了,但是实际上今天我已经领大家看会付宝当中的这个重试代码了,对不对啊,所以这是它的,其实就是一个基本的原理吧,啊这个大家了解一下就可以了,然后呢,存在的问题,刚才其实我已经说了啊,就是因为响应失败,他发起重试,发发起重试就把这些事情又重新做了一遍,重新做了一遍的话,那么就存在没有满足那封性,那么我们怎么去解决呀,我们第一个就是第一个呢,是从我们的数据库层面解决,从数据库层面怎么解决,大家注意啊,就是其实解决这个密等性啊,嗯,可以有很多解决方案,第一数据库,我们回来城市的时候是不是做了两件事情,第一个是修改金额吧,第二个是增加流水吧,好,那么我们首先在这个数据库层面呢,增加流水这块,如果它没有满足这个密等性,没有做密等性判断,它一定会。
08:40
修改金额再增加流水,那么增加流水的过程当中,一定会增加重复的流水号,这个是肯定的,就是他没有判断的情况下,他是不是一定会增加重复的流水号啊,首先我们得保证流水号不能重,流水号重了肯定是隐患,你流水号不重的话,大不了他后台报个错,但是他不会干嘛,他不会把这个金额增加的更多,为什么?因为他俩是一个事务当中的,流水号一旦失败,整个就回滚了,一回滚这个金额。
09:12
多余增加的金额是不是就又给减回去了?明白这个意思吗?所以说,但是这是一个,就是相当于一个脱底的方法,在设计上我们是采用这种设计原则是比较好的,但是你不能把希望寄托于它报错,然后回滚,然后解决你这个密等性的问题,明不明白啊,所以设计上我们要这么设,但是在代码层面,我们还是要判断流水是否存在,避免它走到最后的这一步,那这一步也要做,但是要避免它走到这一步,然后所以呢,我们要首先我们来看一下我们的这个流水号,在transfer这个地方,我们看一下这个transfer number啊,它有个索引,这面呢就创建了一个unitq索引,就是唯一索引,所以一旦你发生发生这个失败同事了啊,一旦没有去判断B的性,那么最终也会在这个地方把我们的这个错误呢,就给它拦截下来了,然后呢,不让这个问题呢恶化下来,对不对啊,所以这是最终的解法,当然了。
10:16
一开始的时候呢,我们还是要进行一个流水是否存在的一个判断,所以呢,我们在穿service里面的写这么一个方法,就是传进去一个流水号,判断一下这个啊流水数据是否存在,我们来返回一个过。那我们来写一下,就是在这个地方找到那个穿。在哪呢,这呢是吧,在这个位置呢,我们添加这么一个方法,然在这里面呢,我们去planet啊,把它implement完了之后呢,我们就在这个里面呢,其实就根据流水号去查这个数据存不存在,如果是存在的话,那么is save,那就返回true对吧,如果不存在的话,那么就返回false哈,所以呢,在这个位置呢,我们就直接查询就行了,Newryper,然后呢,这面我们就放这个transfer flow,然后我们嗯用这个transfer per rapper,对去点这个EQ对吧,然后呢,去判断那个流水号,所以呢,这个transfer这个这个流水号呢,它就叫穿number,好,然后接下来呢,我们把这个a Bill number,这就是流水号,我们把它。
11:45
弹进来,然后我们根据这个产品条件来进行查询,背个matter这个就比较灵活了,我们select one select count select ID都行哈,那比如说我这select count这个啊,然后呢,我把这个穿给它传进去,传进去之后呢,我就得到了一个最终的值啊,那这个值如果它大于零的话,那么就就返回数量啊,所以呢,我就可以直接看看的大鱼。
12:17
如果它大于零的话,那么就返回数对吧?啊,如果不大于零的话,那么就返回bos是不是啊,所以这个呢,就说我们判断当前的这个流水在不在啊好,那接下来呢,我们就可以在我们的这个业务当中,在刚才那个user看service当中,在真正的去执行所有的事情之前,咱们先来干嘛呀,判断流水在不在啊,所以呢,这块我们就穿穿service,然后点is safe穿,然后把那个agent Bill给它传进去,所以这个呢,我们就可以先给它拿出来。先把它拿出来,然后把它传过来,传过来之后呢,我们在这个地方呢,就会得到嗯,一个结果,然后比如说就叫is,然后呢,我们对这个结果呢,进行判断,如果。
13:12
Is save对吧,如果这个已经有了,已经有了的话呢,那我就直接密转性法没了log,咱们写一个写一个那个日志吧,比如说me的姓返回是吧,然后呢,直接返回数就对了,加E啊是S别再调了,已经完事了,前面已经调过了,明白吧啊,所以这面人success就直接就到control抽这面。很出的这面很抽的这面呢,就得到了一个子塞子,然后最终就返回了,总之凡是生子塞子,我们就不希望它再掉了啊好,那这样的话呢,我们这逆整性呢,就就呃就做完了,大家重新启动一下。
我来说两句