1. 程式人生 > 其它 >記錄一次seata中的服務報錯無法回滾問題(xid不一致)

記錄一次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就保持一致了,事務可以回滾

總結:

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