- A模块Mapper直接操作DB得到数据集
- 使用Feign调用B模块
- B模块Mapper操作DB得到数据集
- 合并1,3两步操作或者其他操作
可举例:购物,走DB,库存-1,买家扣钱。
1:库存
2:查询到还有库存,下单,调用支付API扣钱
3:银行卡扣钱
4:判断1、3的结果
分析以上步骤可能抛出异常的情景:
步骤1发生异常,Spring事务回滚
步骤2发生异常,Spring事务回滚
步骤3发生异常,3的服务实现自动回滚,2根据3的返回值来决定是否回滚
步骤四出险异常,1自动回滚,3的操作不会回滚,导致双方数据不同步。不符合同时成功、同时失败原则。
由于Spring的事务是基于单体的,所以Spring的事务并不适用于该情况。解决方法有LCN分布式事务框架和Seata分布式事务框架。
分布式事务原理
TCC(Try-Confirm-Cancel)
- Try阶段:尝试运行,完成所有业务检查(一致性),预留业务必须的资源。
- Confirm阶段:确认需要真正执行的业务,该阶段需要具备幂等设计,Confirm失败后需要进行重试。
- Cancel阶段:取消执行,释放Try阶段预留的业务资源。Cancel阶段的异常和Confirm阶段异常处理方案基本上一致,要求满足幂等设计。
解决方案
在企业级微服务解决方案中,我们可以使用LCN或Seata负责监控每个服务的事务。
以LCN为例:
服务发起方:Feign调用其他服务
@TxTransaction(isStart = true)
@Transactional(rollbackFor = Exception.class)
public void save(){
//do something
}
服务被调用方
@TxTransaction
@Transactional(rollbackFor = Exception.class)
public void save() {
}