|
|
@ -5694,7 +5694,54 @@ Confirm阶段一般需要各个服务自己实现Confirm逻辑:
|
|
|
|
- 用mq消息异步传递子事务状态,最终达到全局事务的完成
|
|
|
|
- 用mq消息异步传递子事务状态,最终达到全局事务的完成
|
|
|
|
- 特点是由发起方决定是否回滚,也就是说只要发起者成功,后续的子事务基本都能成功。比如刷卡后,增加消费积分
|
|
|
|
- 特点是由发起方决定是否回滚,也就是说只要发起者成功,后续的子事务基本都能成功。比如刷卡后,增加消费积分
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
**伪代码:**
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
```java
|
|
|
|
|
|
|
|
执行(事务主题, transId, 参与者){
|
|
|
|
|
|
|
|
name = 参与者.名称()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
mq.setMsg(事务主题, transId, name, 'ping')
|
|
|
|
|
|
|
|
mStatus = 参与者.prepare();
|
|
|
|
|
|
|
|
mq.setMsg(事务主题, transId, name, 'prepare')
|
|
|
|
|
|
|
|
if mStatus:
|
|
|
|
|
|
|
|
excuted = 数据库是否提交(transId, name)
|
|
|
|
|
|
|
|
if not excuted:
|
|
|
|
|
|
|
|
参与者.commit()
|
|
|
|
|
|
|
|
mq.setMsg(事务主题, transId, name, 'commit')
|
|
|
|
|
|
|
|
else:
|
|
|
|
|
|
|
|
参与者.rollback()
|
|
|
|
|
|
|
|
mq.setMsg(事务主题, transId, name, 'rollback')
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
发起者A{
|
|
|
|
|
|
|
|
transId = getTransactionId()
|
|
|
|
|
|
|
|
执行(事务主题X, transId, 参与者A)
|
|
|
|
|
|
|
|
name = 参与者A.名称()
|
|
|
|
|
|
|
|
mq.订阅事件(事务主题X, name).触发函数(e){
|
|
|
|
|
|
|
|
transId = e.transacationId;
|
|
|
|
|
|
|
|
定时任务(事务主题X, transId, name)
|
|
|
|
|
|
|
|
if e.message == 'commit':
|
|
|
|
|
|
|
|
//启动下一个兄弟事务
|
|
|
|
|
|
|
|
mq.setMsg(事务主题X, transId, 参与者B名称, "wake up and work")
|
|
|
|
|
|
|
|
else if e.message == 'rollback':
|
|
|
|
|
|
|
|
mq.delMsg(事务主题X, transId)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
参与者B{
|
|
|
|
|
|
|
|
name = 参与者B.名称()
|
|
|
|
|
|
|
|
mq.订阅事件(事务主题X, name).触发函数(e){
|
|
|
|
|
|
|
|
transId = e.transacationId;
|
|
|
|
|
|
|
|
定时任务(事务主题X, tranId,name)
|
|
|
|
|
|
|
|
if e.message == 'wake up and work':
|
|
|
|
|
|
|
|
执行(事务主题X, transId, 参与者B)
|
|
|
|
|
|
|
|
else if e.message == 'commit':
|
|
|
|
|
|
|
|
mq.delMsg(事务主题X, transId)
|
|
|
|
|
|
|
|
else if e.message == 'rollback':
|
|
|
|
|
|
|
|
//人工处理,因为一般都能执行成功
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
**优/缺点:**
|
|
|
|
**优/缺点:**
|
|
|
|
|
|
|
|
|
|
|
@ -5829,10 +5876,49 @@ Confirm阶段一般需要各个服务自己实现Confirm逻辑:
|
|
|
|
|
|
|
|
|
|
|
|
## Sagas事务模型
|
|
|
|
## Sagas事务模型
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
**原理:(消息)异步 + TCC(部分)**
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Saga事务模型又叫做长时间运行的事务。其核心思想是**「将长事务拆分为多个本地短事务」**,由Saga事务协调器协调,如果正常结束那就正常完成,如果**某个步骤失败,则根据相反顺序一次调用补偿操作**。
|
|
|
|
Saga事务模型又叫做长时间运行的事务。其核心思想是**「将长事务拆分为多个本地短事务」**,由Saga事务协调器协调,如果正常结束那就正常完成,如果**某个步骤失败,则根据相反顺序一次调用补偿操作**。
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
**伪代码:**
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
```java
|
|
|
|
|
|
|
|
执行代码{
|
|
|
|
|
|
|
|
总事务开始()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
new Thread(
|
|
|
|
|
|
|
|
aStatus = 参与者A.冻结资源().commit()
|
|
|
|
|
|
|
|
if aStatus:
|
|
|
|
|
|
|
|
参与者A.扣除资源().commit()
|
|
|
|
|
|
|
|
else
|
|
|
|
|
|
|
|
参与者A.解冻资源().commit()
|
|
|
|
|
|
|
|
).start()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
new Thread(
|
|
|
|
|
|
|
|
bStatus = 参与者A.冻结资源().commit()
|
|
|
|
|
|
|
|
if bStatus:
|
|
|
|
|
|
|
|
参与者B.扣除资源().commit()
|
|
|
|
|
|
|
|
else:
|
|
|
|
|
|
|
|
参与者B.解冻资源().commit()
|
|
|
|
|
|
|
|
).start()
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
自行实现的定时任务{
|
|
|
|
|
|
|
|
if 全部参与者已完成事务:
|
|
|
|
|
|
|
|
if 全部扣除commit成功:
|
|
|
|
|
|
|
|
总事务成功()
|
|
|
|
|
|
|
|
else
|
|
|
|
|
|
|
|
已扣除资源退还()
|
|
|
|
|
|
|
|
总事务失败()
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
## Seate
|
|
|
|
## Seate
|
|
|
|
|
|
|
|
|
|
|
|
**XA和Seata区别**
|
|
|
|
**XA和Seata区别**
|
|
|
|