本文解释Seata中,AT模式和MT模式下的一个一阶段的区别。
根据两阶段行为模式的不同,Seata将分支事务划分为2种:
- Automatic (Branch) Transaction Mode
- Manual (Branch) Transaction Mode
1.AT模式
AT 模式基于 支持本地 ACID 事务 的 关系型数据库:
一阶段 prepare 行为:在本地事务中,一并提交业务数据更新和相应回滚日志记录。
二阶段 commit 行为:马上成功结束,自动 异步批量清理回滚日志。
二阶段 rollback 行为:通过回滚日志,自动 生成补偿操作,完成数据回滚。
2. MT模式
相应的,MT 模式,不依赖于底层数据资源的事务支持:
一阶段 prepare 行为:调用 自定义 的 prepare 逻辑。
二阶段 commit 行为:调用 自定义 的 commit 逻辑。
二阶段 rollback 行为:调用 自定义 的 rollback 逻辑。
所谓 MT 模式,是指支持把 自定义 的分支事务纳入到全局事务的管理中。
3.一阶段解读
在AT模式下,一阶段会做如下几个操作:
1.解析业务sql;
2.获取sql执行前的镜像,前镜像;
3.执行业务sql;
4.获取sql执行后的镜像,后镜像;
5.添加undo_log日志,把前后镜像数据和业务sql相关的信息组成回滚日志,添加到undo_log中;
6.向TC注册分支事务,并申请相关目标数据的全局锁;
7.事务提交,将业务操作和undo_log一起提交;
8.上报分支事务提交结果给TC;
9.释放本地锁;
10.释放数据库连接;
在AT模式下,一阶段,会有如上的多个步骤,以及解析存储undo_log等操作;那么,在MT模式中,由于prepare逻辑有对应的rollback逻辑,显然这里是不用再添加回滚信息的。那么,这MT模式下一阶段的处理逻辑,是如何避免上述操作带来的性能损耗呢?
4.源码分析
在方法拦截器MethodInterceptor接口下,有一个TCC拦截器实现类TccActionInterceptor,这个实现类有一个invoke方法:
@Override
public Object invoke(final MethodInvocation invocation) throws Throwable {
if(!RootContext.inGlobalTransaction()){
//not in transaction
return invocation.proceed();
}
Method method = getActionInterfaceMethod(invocation);
TwoPhaseBusinessAction businessAction = method.getAnnotation(TwoPhaseBusinessAction.class);
//try method
if (businessAction != null) {
//save the xid
String xid = RootContext.getXID();
//clear the context
RootContext.unbind();
try {
Object[] methodArgs = invocation.getArguments();
//Handler the TCC Aspect
Map<String, Object> ret = actionInterceptorHandler.proceed(method, methodArgs, xid, businessAction,
new Callback<Object>() {
@Override
public Object execute() throws Throwable {
return invocation.proceed();
}
});
//return the final result
return ret.get(Constants.TCC_METHOD_RESULT);
} finally {
//recovery the context
RootContext.bind(xid);
}
}
return invocation.proceed();
}
可以看到,在切面的切入点执行之前,和之后,有2个关键操作:
把xid解绑
//save the xid
String xid = RootContext.getXID();
//clear the context
RootContext.unbind();
恢复xid绑定
//recovery the context
RootContext.bind(xid);
这么做的目的是什么呢?
当把xid解绑后,tcc的这个prepare分支事务执行时,框架不会拦截业务sql进行解析,也不会存储前后镜像和生成undo_log日志,(即使使用了代理数据源,也不会)这样,tcc模式下,就避免了一阶段的上述操作带来的损耗。
转载:https://blog.csdn.net/weixin_39800144/article/details/100515957