XA 规范 是 X/Open 组织定义的分布式事务处理(DTP,Distributed Transaction Processing)标准,XA 规范 描述了全局的TM与局部的RM之间的接口,几乎所有主流的数据库都对 XA 规范 提供了支持。
两个阶段的提交
XA是规范,目前主流数据库都实现了这种规范,实现的原理都是基于两阶段提交。
正常情况下:
异常情况下:
一阶段:
- 事务协调者通知每个事物参与者执行本地事务
- 本地事务执行完成后报告事务执行状态给事务协调者,此时事务不提交,继续持有数据库锁
二阶段:
事务协调者基于一阶段的报告来判断下一步操作
事务的强一致性,满足ACID原则。
- 常用数据库都支持,实现简单,并且没有代码侵入
XA模式的缺点是什么?
- 因为一阶段需要锁定数据库资源,等待二阶段结束才释放,性能较差
- 依赖关系型数据库实现事务,数据库不支持这么做就不行
实现XA模式
案例说明:
看这篇文章的项目流程图
Seata的starter已经完成了XA模式的自动装配,步骤如下:
修改application.yml文件(每个参与事务的微服务都要设置),开启XA模式:
seata:
data-source-proxy-mode: XA
给发起全局事务的入口方法添加
@GlobalTransactional
注解:
案例中的全局入口就是下订单的入口
@Override
@GlobalTransactional
public Long create(Order order) {
// 创建订单
orderMapper.insert(order);
try {
// 扣用户余额
accountClient.deduct(order.getUserId(), order.getMoney());
// 扣库存
storageClient.deduct(order.getCommodityCode(), order.getCount());
} catch (FeignException e) {
log.error("下单失败,原因:{}", e.contentUTF8(), e);
throw new RuntimeException(e.contentUTF8(), e);
}
return order.getId();
}
- 重启服务测试
数据库中用户有1000元,库存有10个,我们买20个,花费200元,结果失败了。
看代码日志,本来扣款过的,但是减库存失败,扣款就回滚了