記錄一次seata中的服務報錯無法回滾問題(xid不一致)


背景:

公司接手了一個項目,在對其進行優化時,由於之前項目沒有考慮到分布式事務,因此綜合考慮后采用seata(1.3)來作為分布式事務

問題:

簡單點就是AB兩個服務,其中A服務報錯,B服務能正常提交

問題猜想:

通過斷點以及日志查看,發現AB兩個服務的xid不一致,因此着重考慮如何讓他們保持一致

 

問題還原:

本地A服務測試代碼:

A服務調用B服務,其中A服務中控制它報錯

   public Object buyService() {
       TeamEntity teamEntity = new TeamEntity();
       teamEntity.setName("服務A提交");
       teamDao.saveAndFlush(teamEntity) ;
       consultService.buyService2();
       int i = 1 /0 ;
       return null;
  }

本地B服務測試代碼:

    public Response buyService2(){
       AudioConsult audioConsult1 = new AudioConsult();
       audioConsult1.setOrderItem("01-299999999222");
       AudioConsultPo audioConsultPo = audioConsultDTOConverterUtils.toPO(audioConsult1);
//     服務B提交
       audioConsultDao.save(audioConsultPo);
       return Response.build().success("success");
  }

提交后A服務日志:

===== 2021-07-05 16:56:34.023 ===== INFO  io.seata.core.rpc.processor.client.RmBranchRollbackProcessor Line:56  - rm handle branch rollback process:xid=192.168.1.31:8091:155357727480213504,branchId=155357728667201537,branchType=AT,resourceId=jdbc:mysql:xxxx
===== 2021-07-05 16:56:34.025 ===== INFO  io.seata.rm.AbstractRMHandler Line:123 - Branch Rollbacking: 192.168.1.31:8091:155357727480213504 155357728667201537

 

提交后B服務日志:

===== 2021-07-05 16:56:09.934 ===== INFO  io.seata.rm.AbstractRMHandler Line:104 - Branch commit result: PhaseTwo_Committed
===== 2021-07-05 16:56:09.934 ===== DEBUG io.seata.core.rpc.processor.client.RmBranchCommitProcessor Line:65  - branch commit result:xid=192.168.1.31:8091:155357730458169344,branchId=155357731833901057,branchStatus=PhaseTwo_Committed,result code =Success,getMsg =null

 

可以看到A,B兩個服務的xid並不一致,同時在數據庫中也並沒有找到B服務的xid,如下圖:

 

 

 

解決方法:

在A服務中拿到xid,並傳給B服務,代碼如下

A服務中的代碼修改為:

 @Override
   public Object buyService() {
       String xid = GlobalTransactionContext.getCurrentOrCreate().getXid();
       RootContext.bind(xid);
       TeamEntity teamEntity = new TeamEntity();
       teamEntity.setName("服務A提交");
       TeamEntity save = teamDao.saveAndFlush(teamEntity) ;
       Object o = consultService.buyService2(xid);
       int i = 1 /0 ;
       return o;
  }

 

B服務中的代碼修改為:

 public Response buyService2(@RequestParam("xid") String xid){
       RootContext.bind(xid);
       AudioConsult audioConsult1 = new AudioConsult();
       audioConsult1.setOrderItem("01-299999999222");
       AudioConsultPo audioConsultPo = audioConsultDTOConverterUtils.toPO(audioConsult1);
//     服務B提交
       audioConsultDao.save(audioConsultPo);
       XidResource.cleanXid(xid);
       return Response.build().success("success");

  }

 

這樣兩個服務的xid就保持一致了,事務可以回滾

總結:

雖然問題解決了,但是我覺得這肯定不是最佳的解決方法!在同一個注冊中心下的兩個服務應該不會這么麻煩,所以先將這個解決方法記錄一下,各位大佬如果有更好的解決方法麻煩提供一下


免責聲明!

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



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