记录一次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,如下图:

记录一次seata中的服务报错无法回滚问题(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就保持一致了,事务可以回滚

总结:

虽然问题解决了,但是我觉得这肯定不是最佳的解决方法!在同一个注册中心下的两个服务应该不会这么麻烦,所以先将这个解决方法记录一下,各位大佬如果有更好的解决方法麻烦提供一下

上一篇:Seata1.4配置及使用


下一篇:Java面试题总结三(2021最新)