背景:
公司接手了一个项目,在对其进行优化时,由于之前项目没有考虑到分布式事务,因此综合考虑后采用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就保持一致了,事务可以回滚
总结:
虽然问题解决了,但是我觉得这肯定不是最佳的解决方法!在同一个注册中心下的两个服务应该不会这么麻烦,所以先将这个解决方法记录一下,各位大佬如果有更好的解决方法麻烦提供一下