美文网首页
事务遇到第三方API请求如何处理

事务遇到第三方API请求如何处理

作者: 一击必中 | 来源:发表于2021-06-23 14:27 被阅读0次

    一、使用场景 :

    1.功能实现需多次进行数据库操作

    2.方法中包含请求第三方API接口

    二、第三方API使用遇到的场景

    (1) 第三方API成功或失败不影响主体业务的进行,如消息推送

    处理方法: 把消息推送的方法摘出来,进行异步处理,避免请求出错影响主体业务流程;

    注意 : 需把异步方法抽取到另一个类中,否则@Async不生效

    异步处理
    image.png

    (2) 第三方API与主体业务不可分割(如员工调动,员工离职相关API)

    处理展示 :

    ① 请求API,根据API返回结果进行业务处理(进行数据库操作)

    ② 先进行数据库操作,再请求第三方的API

    思考:①和②两种处理方式的区别?


    ① 请求API,根据API返回结果进行业务处理(进行数据库操作)

    问题 : 如果API接口返回错误,则无需往下执行后续业务逻辑处理,直接终止

          但是,如果API请求通过, 后续业务逻辑执行一旦出错,进行回滚, API无法回滚 , 导致事务不一致
    
    例如员工离职,已从钉钉架构中移除员工,但是数据库状态回滚为正常状态,造成数据不一致
    
    ② 先进行数据库操作,再请求第三方的API

    优点:请求第三方API发生错误时,可以回滚数据库数据;

    可以得出结论第①种顺序(先API,后修改库)是有致命缺陷的,这种处理方式在代码里禁止使用!

    二丶遇到API如何应该如何做?

    1、API请求共性

    (1)、明确成功

    明确成功的意思很明显,这也是我们最常用到的成功情况,当第三方给你返回200状态码或OK时,就可以是明确成功了。

    可能存在的问题:请求时间过长

    (2)、明确失败

    明确成功的意思很明显,这也是我们最常用到的失败情况,当第三方给你返回非200状态码或OK时,就可以是明确失败了,你就可以处理回滚了。

    可能存在的问题:请求时间过长

    (3)、结果未知

    当你请求发过去了,因为第三方处理时间过长(可能是他们服务器有问题,也可能是业务复杂),导致连接直接断开了,谁也不知道他那边是否处理完成了。

    可能存在的问题:超时情况

    2、API请求存在的问题

    (1)、API请求超时无法处理

    请求API超时,程序判定修改失败,事务回滚, 但是API方法实际还在执行,导致数据不一致。

    (2)、API请求时间过长,长时间占用库问题

    虽然API请求成功了,但是20s才处理完成,因为在上面我们对自己库的操作已经在事务里面了,还未提交,所以将导致我们的操作被锁定20s,当堆积的多了,就会产生问题。

    3、解决方案:

    方案1: 解决超时问题

    如果有条件- 调用方和被调用方协调好,可以为调用方提供回调或轮询查询接口

    回调:比如超级店长调用千云,千云给超级店长提供一个回调接口,返回处理结果

    轮询:超级店长定时去请求千云,获取结果

    这样做的好处?

    通过被调用方提供的回调或轮询功能,我们能够明确的知道自己调用是否完全成功或完全失败,不会存在模棱两个的情况。保证了第三方API结果的确定性,为事务的一致性构建了前提。

    这样做的缺点

    这样做没有缺点,正规的程序都会提供,唯一的缺点就是不正规的可能不提供,这也就要求我们在为别人提供业务接口的时候,要根据业务的重要程度,为他人提供回调或轮询方法。

    方案2:解决库占用问题

    启用编程式事务,包裹住对数据库修改的操作

        // 方法上不加事务
        public SimpleMessage testA() {
            // 进行校验参数,一些查询
            Select ***
    
            // 开启事务,进行一些数据库修改操作
            transactionTemplate.execute(status -> {
                update ***
                update ***
    
                return null;
            });
            // 进行第三方API请求
            httpUtils.post***;
            return new SimpleMessage(ErrorCodeEnum.OK);
        }
    
    使用方法

    这样做的好处?

    自己库的多个操作数据已经执行完成,事务也已经提交释放,且api请求不在事务中,自己的库不会被锁。

    这样做的缺点

    虽然库不被占用了,但是第三方请求如果失败了,事务仍然会不一致。而且还是无法解决超时问题,有可能存在超时情况,结果未知导致事务不一致。

    方案3:在①和②的基础上改进

    在方案②的基础上对失败的情况恢复处理(使用编程式事务)

    在方案①的基础上使用 回调/轮询处理

        // 方法上不加事务
        public SimpleMessage testA() {
            // 进行校验参数,一些查询
            Select ***
    
            // 开启事务,进行一些数据库修改操作
            transactionTemplate.execute(status -> {
                update num = 2 where ***
                update ***
    
                return null;
            });
            // 进行第三方API请求
            httpUtils.post***
            // 根据API请求返回结果, 如果失败则对数据进行回退操作
            // 开启事务,进行数据恢复操作
            transactionTemplate.execute(status -> {
                update num = 1 where ***
                update ***
                return null;
            });
            return new SimpleMessage(ErrorCodeEnum.OK);
        }
    

    提示

    TransactionTemplate执行时,不论发生受检查的异常(Exception),还是不受检查的异常(RuntimeException),都会执行回滚操作,所以无需担心事务不提交问题导致的重大bug。

    这样做的好处

    1、防止了库被占用,且得到失败的结果后能进行手动回滚。

    这样做的缺点

    1.写起来比较麻烦

    2.如果第三方不提供回调或轮询,还是没办法保证事务一致性,所以第三方很重要。如果第三方提供,搭配①方案使用,就是完美解决方案,如果第三方不提供,将不存在完美解决方案,也间接说明这个业务不是很重要且开发人员很拉跨。

    相关文章

      网友评论

          本文标题:事务遇到第三方API请求如何处理

          本文链接:https://www.haomeiwen.com/subject/wgccjltx.html