如何与第三方接口保持数据一致性
Posted Fly , Mason ! ! !
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何与第三方接口保持数据一致性相关的知识,希望对你有一定的参考价值。
大家经常遇到这样的需求,尤其是支付中心接口的时候:
查询满足某种条件的订单,调用第三方接口成功,更改订单状态。
常见实现示例
task1:
orders = queyrOrder(...); //查询已离店的订单 for (Map<String, Object> order : orders) { try { con.setAutoCommit( false ); String orderNo = (String) order.get( "order_no" ); // 调用支付中心返现接口 callCommission(order); //无论是网络异常还是返回结果失败,都抛异常 // 更改订单状态 cashedOrder(con, order); //更改订单状态 con.commit(); } |
task 2
orders = queyrOrder(...); //查询“返现中”的订单 for (Map<String, Object> order : orders) { con.setAutoCommit( false ); // 调用返现任务 callCommission(order); // 更改订单状态 cashedOrder(con, order); con.commit(); } |
示例的问题
- 在事务中存在远程调用,容易导致事务时间过长
- 在callCommission 和 cashedOrder之间,是否有其他操作能改变该订单状态? 如果有,是否会出现多次调用第三方的问题?
- 第三方接口特性未知
设计方案
往两个方面思考
- 自己系统本身数据一致性
- 如果调用第三方接口 和 更新自己系统数据 之间任何一个环节 出异常了。比如:应用重启,机房网络问题等。如何保证第三方接口和自己系统的数据一致性?
方案
- 加锁,方案有:版本号乐观锁、select for update 悲观锁。
延伸问题:在原表上执行task,还是队列表? - 第三方接口需要什么特性才能保证数据一致性? 要考虑网络超时问题、应用发布重启、并发等问题。
- 回调
- 提供结果查询
- 幂等性
重构后的示例1:
(幂等接口的方案)
queueOrders = queryQueueOrders(); for (QueueOrder order : queueOrders){ callApi() startTransaction(); lock(order); updateStatus() commitTransaction(); } |
(提供结果查询的API接口的方案)
queueOrders = queryQueueOrders(); for (QueueOrder order : queueOrders){ try { startTransaction(); if (isBeingProcess(order)){ Result r = queryAPIResult(); if (r.success()){ return ; } } lock(order); callApi() updateStatus(); } finally { commitTransaction(); } } |
注意:该示例依然有“在事务中调用远程接口的问题”
http://www.cnblogs.com/NanguoCoffee/archive/2013/03/30/2990918.html
以上是关于如何与第三方接口保持数据一致性的主要内容,如果未能解决你的问题,请参考以下文章
如何更新导航抽屉中的有状态小部件,同时在 Android 中保持与片段相同的类?
GraphQL:Apollo 客户端缓存如何工作以保持与服务器的数据一致性?
终于懂了:Delphi重定义消息结构随心所欲,只需要前4个字节是消息编号就行了,跟Windows消息虽然尽量保持一致,但其实相互没有特别大的关系。有了这个,就有了主动,带不带句柄完全看需要。(代码片段