XA模式:
XA模式采用的是俩阶段提交:
正常:
异常:
一阶段:
-
事务协调者通知每个事物参与者执行本地事务
-
本地事务执行完成后报告事务执行状态给事务协调者,此时事务不提交,继续持有数据库锁
注意:本方法依赖数据库的未提交机制(内存中)将sql语句执行而不提交 等全部执行成功再提交
二阶段:
-
事务协调者基于一阶段的报告来判断下一步操作
-
如果一阶段都成功,则通知所有事务参与者,提交事务
-
如果一阶段任意一个参与者失败,则通知所有事务参与者回滚事务
-
RM一阶段的工作:
① 注册分支事务到TC
② 执行分支业务sql但不提交
③ 报告执行状态到TC
TC二阶段的工作:
-
TC检测各分支事务执行状态
a.如果都成功,通知所有RM提交事务
b.如果有失败,通知所有RM回滚事务
RM二阶段的工作:
-
接收TC指令,提交或回滚事务
优缺点:
XA模式的优点是什么?
-
事务的强一致性,满足ACID原则。
-
常用数据库都支持,实现简单,并且没有代码侵入
XA模式的缺点是什么?
-
因为一阶段需要锁定数据库资源,等待二阶段结束才释放,性能较差
-
依赖关系型数据库实现事务
XA快速入门:
Seata的starter已经完成了XA模式的自动装配,实现非常简单,步骤如下:
(没完成的看上一篇!!!!)
1)修改application.yml文件(每个参与事务的微服务),开启XA模式:
seata:
data-source-proxy-mode: XA
2)给发起全局事务的入口方法添加@GlobalTransactional注解:
本例中是OrderServiceImpl中的create方法.
@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();
}
}
3)重启服务并测试
重启order-service,再次测试,发现无论怎样,三个微服务都能成功回滚。
注意:本方法依赖数据库的未提交机制(内存中)将sql语句执行而不提交 等全部执行成功再提交