如何與第三方接口保持數據一致性


場景

大家經常遇到這樣的需求,尤其是支付中心接口的時候:

查詢滿足某種條件的訂單,調用第三方接口成功,更改訂單狀態。

常見實現示例

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();            

 }

  

示例的問題
  1. 在事務中存在遠程調用,容易導致事務時間過長
  2. 在callCommission 和 cashedOrder之間,是否有其他操作能改變該訂單狀態? 如果有,是否會出現多次調用第三方的問題?
  3. 第三方接口特性未知
設計方案

往兩個方面思考

  1. 自己系統本身數據一致性
  2. 如果調用第三方接口 和 更新自己系統數據 之間任何一個環節 出異常了。比如:應用重啟,機房網絡問題等。如何保證第三方接口和自己系統的數據一致性?

方案

  1. 加鎖,方案有:版本號樂觀鎖、select for update 悲觀鎖。
    延伸問題:在原表上執行task,還是隊列表?
  2. 第三方接口需要什么特性才能保證數據一致性? 要考慮網絡超時問題、應用發布重啟、並發等問題。
  • 回調
  • 提供結果查詢
  • 冪等性
重構后的示例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();
   }
}
 
          

注意:該示例依然有“在事務中調用遠程接口的問題”


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM