本文旨在针对Seata框架的TCC模式的源码进行讲解分析,在此不过多介绍Seata框架。
如果想了解更多有关Seata框架的细节,建议可以阅读我的另外一篇博客:Seata框架源码分析——AT模式
为了更新方便之后的源码分析讲解,首先来看下TCC模式的使用示例:
与AT模式的使用非常类似,TCC模式都是使用注解达到分布式事务控制的效果,使用成本非常低。
业务调用方在接口方法上使用@GlobalTransactional注解,开启全局事务
@Service
public class OrderServiceImpl implements OrderService {
@Autowired
OrderDao orderDao;
@DubboReference
AccountService accountService;
@DubboReference
StorageService storageService;
@Override
@GlobalTransactional
public boolean dealTCC(Order order) {
// 扣减账户
Account account = new Account();
account.setAccountId(order.getAccountId());
account.setUsed(order.getAmount());
accountService.prepare(null, account);
// 扣减库存
Storage storage = new Storage();
storage.setStorageId(order.getStorageId());
storage.setUsed(1);
storageService.prepare(null, storage);
// 保存订单
this.orderDao.insert(order);
return true;
}
}
业务提供方则在接口方法上使用@TwoPhaseBusinessAction注解,同时指定同个接口中分支事务提交和回滚的方法名:
public interface AccountService {
/**
* AT 模式
*
* @param account
* @return
*/
boolean dealAT(Account account);
/**
* TCC 模式try方法,用于冻结操作
*
* @param actionContext
* @param account
* @return
*/
@TwoPhaseBusinessAction(name = "account-tx", commitMethod = "commit", rollbackMethod = "rollback")
boolean prepare(BusinessActionContext actionContext, @BusinessActionContextParameter(paramName = "account") Account account);
/**
* TCC 模式commit方法,当全部分支事物准备完毕后,TC事务控制器会通知调用此方法提交
*
* @param actionContext
* @return
*/
boolean commit(BusinessActionContext actionContext);
/**
* TCC 模式rollback方法,当全局事务需要回滚的时候,TC事务控制器会通知调用此方法回滚,而不再使用undo日志
*
* @param actionContext
* @return
*/
boolean rollback(BusinessActionContext actionContext);
}
有了以上使用示例的了解,接下来就是针对其中的源码实现细节进行分析讲解。
Seata模式很好的融入了Spring框架,因此在系统启动时,会扫描相关的Bean进行初始化,并注入,而这个类就是GlobalTransactionScanner:
public class GlobalTransactionScanner extends AbstractAutoProxyCreator
implements ConfigurationChangeListener, InitializingBean, ApplicationContextAware, DisposableBean {
...
}
在GlobalTransactionScanner中最主要的动作有两个:
@Override
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
if (!doCheckers(bean, beanName)) { // bean校验
return bean;
}
try {
synchronized (PROXYED_SET) { // 同步的方式初始化bean
if (PROXYED_SET.contains(beanName)) {
return bean;
}
interceptor = null; // 拦截器
// 判断初始化的bean是属于TCC模式,还是AT模式。不同的模式需要初始化的拦截器不同
// TCC模式:TccActionInterceptor
// AT模式:GlobalTransactionalInterceptor
if (TCCBeanParserUtils.isTccAutoProxy(bean, beanName, applicationContext)) { // TCC模式
interceptor = new TccActionInterceptor(TCCBeanParserUtils.getRemotingDesc(beanName));
ConfigurationCache.addConfigListener(ConfigurationKeys.DISABLE_GLOBAL_TRANSACTION, (ConfigurationChangeListener)interceptor);
} else { // AT模式
Class<?> serviceInterface = SpringProxyUtils.findTargetClass(bean);
Class<?>[] interfacesIfJdk = SpringProxyUtils.findInterfaces(bean);
if (!existsAnnotation(new Class[]{serviceInterface}) && !existsAnnotation(interfacesIfJdk)) {
return bean;
}
if (globalTransactionalInterceptor == null) {
globalTransactionalInterceptor = new GlobalTransactionalInterceptor(failureHandlerHook);
ConfigurationCache.addConfigListener(ConfigurationKeys.DISABLE_GLOBAL_TRANSACTION, (ConfigurationChangeListener)globalTransactionalInterceptor);
}
interceptor = globalTransactionalInterceptor;
}
LOGGER.info("Bean[{}] with name [{}] would use interceptor [{}]", bean.getClass().getName(), beanName, interceptor.getClass().getName());
if (!AopUtils.isAopProxy(bean)) {
bean = super.wrapIfNecessary(bean, beanName, cacheKey);
} else {
AdvisedSupport advised = SpringProxyUtils.getAdvisedSupport(bean);
Advisor[] advisor = buildAdvisors(beanName, getAdvicesAndAdvisorsForBean(null, null, null));
int pos;
for (Advisor avr : advisor) {
// Find the position based on the advisor's order, and add to advisors by pos
pos = findAddSeataAdvisorPosition(advised, avr);
advised.addAdvisor(pos, avr);
}
}
PROXYED_SET.add(beanName);
return bean;
}
} catch (Exception exx) {
throw new RuntimeException(exx);
}
}
由以上wrapIfNecessary方法可以看到,初始化拦截器的关键点是TCCBeanParserUtils.isTccAutoProxy方法,判断该Bean是否属于TCC模式:
public static boolean isTccAutoProxy(Object bean, String beanName, ApplicationContext applicationContext) {
boolean isRemotingBean = parserRemotingServiceInfo(bean, beanName); // 解析bean信息
//get RemotingBean description
RemotingDesc remotingDesc = DefaultRemotingParser.get().getRemotingBeanDesc(beanName);
//is remoting bean
if (isRemotingBean) {
if (remotingDesc != null && remotingDesc.getProtocol() == Protocols.IN_JVM) {
//LocalTCC
return isTccProxyTargetBean(remotingDesc); // 判断bean是否属于TCC模式
} else {
// sofa:reference / dubbo:reference, factory bean
return false;
}
} else {
if (remotingDesc == null) {
//check FactoryBean
if (isRemotingFactoryBean(bean, beanName, applicationContext)) {
remotingDesc = DefaultRemotingParser.get().getRemotingBeanDesc(beanName);
return isTccProxyTargetBean(remotingDesc);
} else {
return false;
}
} else {
return isTccProxyTargetBean(remotingDesc);
}
}
}
解析bean,并注册TCC模式的RM资源管理器:
protected static boolean parserRemotingServiceInfo(Object bean, String beanName) {
RemotingParser remotingParser = DefaultRemotingParser.get().isRemoting(bean, beanName);
if (remotingParser != null) {
return DefaultRemotingParser.get().parserRemotingServiceInfo(bean, beanName, remotingParser) != null; // 解析bean信息
}
return false;
}
public RemotingDesc parserRemotingServiceInfo(Object bean, String beanName, RemotingParser remotingParser) {
RemotingDesc remotingBeanDesc = remotingParser.getServiceDesc(bean, beanName);
if (remotingBeanDesc == null) {
return null;
}
remotingServiceMap.put(beanName, remotingBeanDesc); // 将bean缓存起来
Class<?> interfaceClass = remotingBeanDesc.getInterfaceClass(); // 获取bean接口类
Method[] methods = interfaceClass.getMethods(); // 获取bean接口类的所有方法
if (remotingParser.isService(bean, beanName)) {
try {
Object targetBean = remotingBeanDesc.getTargetBean();
for (Method m : methods) { // 遍历方法
// 判断方法上是否有标注@TwoPhaseBusinessAction注解
TwoPhaseBusinessAction twoPhaseBusinessAction = m.getAnnotation(TwoPhaseBusinessAction.class);
if (twoPhaseBusinessAction != null) {
// 注解不为空,说明该bean属于TCC模式,以下封装TCC相关资源信息,并进行注册
TCCResource tccResource = new TCCResource();
tccResource.setActionName(twoPhaseBusinessAction.name());
tccResource.setTargetBean(targetBean);
tccResource.setPrepareMethod(m);
tccResource.setCommitMethodName(twoPhaseBusinessAction.commitMethod()); // 设置指定的提交方法名
tccResource.setCommitMethod(interfaceClass.getMethod(twoPhaseBusinessAction.commitMethod(),
twoPhaseBusinessAction.commitArgsClasses())); // 设置指定的提交方法对象
tccResource.setRollbackMethodName(twoPhaseBusinessAction.rollbackMethod()); // 设置指定的回滚方法名
tccResource.setRollbackMethod(interfaceClass.getMethod(twoPhaseBusinessAction.rollbackMethod(),
twoPhaseBusinessAction.rollbackArgsClasses())); // 设置指定的回滚方法对象
// 设置提交/回滚方法参数类型
tccResource.setCommitArgsClasses(twoPhaseBusinessAction.commitArgsClasses());
tccResource.setRollbackArgsClasses(twoPhaseBusinessAction.rollbackArgsClasses());
// set phase two method's keys
tccResource.setPhaseTwoCommitKeys(this.getTwoPhaseArgs(tccResource.getCommitMethod(),
twoPhaseBusinessAction.commitArgsClasses()));
tccResource.setPhaseTwoRollbackKeys(this.getTwoPhaseArgs(tccResource.getRollbackMethod(),
twoPhaseBusinessAction.rollbackArgsClasses()));
// 注册TCC资源,在后期需要获取此资源,调用其中提交/回滚方法
DefaultResourceManager.get().registerResource(tccResource);
}
}
} catch (Throwable t) {
throw new FrameworkException(t, "parser remoting service error");
}
}
if (remotingParser.isReference(bean, beanName)) {
//reference bean, TCC proxy
remotingBeanDesc.setReference(true);
}
return remotingBeanDesc;
}
注册TCC资源:
@Override
public void registerResource(Resource resource) {
getResourceManager(resource.getBranchType()).registerResource(resource);
}
@Override
public void registerResource(Resource resource) {
TCCResource tccResource = (TCCResource)resource;
tccResourceCache.put(tccResource.getResourceId(), tccResource); // 本地缓存TCC资源
super.registerResource(tccResource); // 调用父类注册方法
}
@Override
public void registerResource(Resource resource) {
// TC服务端注册TCC资源
RmNettyRemotingClient.getInstance().registerResource(resource.getResourceGroupId(), resource.getResourceId());
}
经过TCC资源的注册,可以知道在分支事务的本地会根据资源id对资源进行缓存,以及TC服务端针对该资源注册(远程注册逻辑不是重点,不分析,有兴趣的朋友可以自行研究DefaultServerMessageListenerImp.onRegRmMessage方法)。
对于注解来说,首先拦截的业务调用方的@GlobalTransactional。拦截的类方法则是GlobalTransactionalInterceptor.invoke
@Override
public Object invoke(final MethodInvocation methodInvocation) throws Throwable {
Class<?> targetClass = methodInvocation.getThis() != null ? AopUtils.getTargetClass(methodInvocation.getThis()) : null;
Method specificMethod = ClassUtils.getMostSpecificMethod(methodInvocation.getMethod(), targetClass);
if (specificMethod != null && !specificMethod.getDeclaringClass().equals(Object.class)) {
final Method method = BridgeMethodResolver.findBridgedMethod(specificMethod);
final GlobalTransactional globalTransactionalAnnotation = getAnnotation(method, targetClass, GlobalTransactional.class); // 获取拦截方法上的@GlobalTransactional注解
final GlobalLock globalLockAnnotation = getAnnotation(method, targetClass, GlobalLock.class);
boolean localDisable = disable || (degradeCheck && degradeNum >= degradeCheckAllowTimes);
if (!localDisable) { // 判断本地是否允许开启分布式事务
if (globalTransactionalAnnotation != null) { // 注解不为空,则说明拦截的方法上有@GlobalTransactional注解,开启分布式事务
return handleGlobalTransaction(methodInvocation, globalTransactionalAnnotation);
} else if (globalLockAnnotation != null) {
return handleGlobalLock(methodInvocation, globalLockAnnotation);
}
}
}
return methodInvocation.proceed(); // 本地不允许开启分布式事务/拦截方法上没有@GlobalTransactional注解,则按原方法执行
}
全局事务拦截这部分源码与AT模式如出一辙,最后具体是通过调用TransactionalTemplate.execute方法实现本地事务执行:
public Object execute(TransactionalExecutor business) throws Throwable {
TransactionInfo txInfo = business.getTransactionInfo(); // 获取事务相关信息
if (txInfo == null) {
throw new ShouldNeverHappenException("transactionInfo does not exist");
}
GlobalTransaction tx = GlobalTransactionContext.getCurrent(); // 获取当前事务对象(主要是通过全局事务XID进行判断)
Propagation propagation = txInfo.getPropagation(); // 获取事务信息中的事务传播级别
SuspendedResourcesHolder suspendedResourcesHolder = null;
try {
// 针对各个事务级别做特殊处理,在此不多讲,继续往下看
switch (propagation) {
case NOT_SUPPORTED:
// If transaction is existing, suspend it.
if (existingTransaction(tx)) {
suspendedResourcesHolder = tx.suspend();
}
// Execute without transaction and return.
return business.execute();
case REQUIRES_NEW:
// If transaction is existing, suspend it, and then begin new transaction.
if (existingTransaction(tx)) {
suspendedResourcesHolder = tx.suspend();
tx = GlobalTransactionContext.createNew();
}
// Continue and execute with new transaction
break;
case SUPPORTS:
// If transaction is not existing, execute without transaction.
if (notExistingTransaction(tx)) {
return business.execute();
}
// Continue and execute with new transaction
break;
case REQUIRED:
// If current transaction is existing, execute with current transaction,
// else continue and execute with new transaction.
break;
case NEVER:
// If transaction is existing, throw exception.
if (existingTransaction(tx)) {
throw new TransactionException(
String.format("Existing transaction found for transaction marked with propagation 'never', xid = %s"
, tx.getXid()));
} else {
// Execute without transaction and return.
return business.execute();
}
case MANDATORY:
// If transaction is not existing, throw exception.
if (notExistingTransaction(tx)) {
throw new TransactionException("No existing transaction found for transaction marked with propagation 'mandatory'");
}
// Continue and execute with current transaction.
break;
default:
throw new TransactionException("Not Supported Propagation:" + propagation);
}
if (tx == null) { // 当前事务对象为空,说明当前未开启事务,新建事务对象
tx = GlobalTransactionContext.createNew();
}
GlobalLockConfig previousConfig = replaceGlobalLockConfig(txInfo);
try {
beginTransaction(txInfo, tx); // 开启事务(重点)
Object rs;
try {
rs = business.execute(); // 执行原方法
} catch (Throwable ex) {
completeTransactionAfterThrowing(txInfo, tx, ex); // 原方法执行异常,回滚(重点)
throw ex;
}
commitTransaction(tx); // 原方法执行无异常,提交(重点)
return rs;
} finally {
// clear
resumeGlobalLockConfig(previousConfig);
triggerAfterCompletion();
cleanUp();
}
} finally {
// If the transaction is suspended, resume it.
if (suspendedResourcesHolder != null) {
tx.resume(suspendedResourcesHolder);
}
}
}
在上面的execute方法中看到,开启事务、执行原方法、成功提交事务、失败回滚事务 这些关键方法。但是对于TCC模式来说,只有当business.execute()执行原方法时,才会调用到其中标注了@TwoPhaseBusinessAction注解方法,该注解才会被拦截增强,TCC模式才会真正生效。
而拦截这个注解的类方法,就是本文开头所讲解的初始化拦截器TccActionInterceptor.invoke:
@Override
public Object invoke(final MethodInvocation invocation) throws Throwable {
if (!RootContext.inGlobalTransaction() || disable || RootContext.inSagaBranch()) { // 检查是否允许启用全局事务
return invocation.proceed(); // 禁止启用,直接原方法执行
}
Method method = getActionInterfaceMethod(invocation);
TwoPhaseBusinessAction businessAction = method.getAnnotation(TwoPhaseBusinessAction.class); // 获取方法上的TwoPhaseBusinessAction注解
if (businessAction != null) { // 注解不为空,则说明是TCC模式
String xid = RootContext.getXID(); // 获取全局事务ID
BranchType previousBranchType = RootContext.getBranchType();
if (BranchType.TCC != previousBranchType) {
RootContext.bindBranchType(BranchType.TCC);
}
try {
// 处理TCC模式方法
return actionInterceptorHandler.proceed(method, invocation.getArguments(), xid, businessAction, invocation::proceed);
} finally {
//if not TCC, unbind branchType
if (BranchType.TCC != previousBranchType) {
RootContext.unbindBranchType();
}
//MDC remove branchId
MDC.remove(RootContext.MDC_KEY_BRANCH_ID);
}
}
return invocation.proceed(); // 注解为空,则说明不是TCC模式,直接原方法执行
}
TCC注解拦截处理,注册分支事务,并返回绑定分支事务ID:
public Object proceed(Method method, Object[] arguments, String xid, TwoPhaseBusinessAction businessAction, Callback<Object> targetCallback) throws Throwable {
// 封装TCC上下文信息
String actionName = businessAction.name();
BusinessActionContext actionContext = new BusinessActionContext();
actionContext.setXid(xid);
actionContext.setActionName(actionName);
// 注册分支事务,并返回绑定分支事务ID
String branchId = doTccActionLogStore(method, arguments, businessAction, actionContext);
actionContext.setBranchId(branchId);
MDC.put(RootContext.MDC_KEY_BRANCH_ID, branchId);
Class<?>[] types = method.getParameterTypes();
int argIndex = 0;
for (Class<?> cls : types) {
if (cls.isAssignableFrom(BusinessActionContext.class)) {
arguments[argIndex] = actionContext;
break;
}
argIndex++;
}
BusinessActionContext previousActionContext = BusinessActionContextUtil.getContext(); // 获取前一个上下文对象(即当前上下文对象)
try {
BusinessActionContextUtil.setContext(actionContext); // 替换上下文对象
if (businessAction.useTCCFence()) {
try {
// Use TCC Fence, and return the business result
return TCCFenceHandler.prepareFence(xid, Long.valueOf(branchId), actionName, targetCallback);
} catch (FrameworkException | UndeclaredThrowableException e) {
Throwable originException = e.getCause();
if (originException instanceof FrameworkException) {
LOGGER.error("[{}] prepare TCC fence error: {}", xid, originException.getMessage());
}
throw originException;
}
} else {
//Execute business, and return the business result
return targetCallback.execute();
}
} finally {
try {
//to report business action context finally if the actionContext.getUpdated() is true
BusinessActionContextUtil.reportContext(actionContext);
} finally {
if (previousActionContext != null) {
// recovery the previous action context
BusinessActionContextUtil.setContext(previousActionContext);
} else {
// clear the action context
BusinessActionContextUtil.clear();
}
}
}
}
protected String doTccActionLogStore(Method method, Object[] arguments, TwoPhaseBusinessAction businessAction, BusinessActionContext actionContext) {
// 初始化上下文
String actionName = actionContext.getActionName();
String xid = actionContext.getXid();
Map<String, Object> context = fetchActionRequestContext(method, arguments);
context.put(Constants.ACTION_START_TIME, System.currentTimeMillis());
initBusinessContext(context, method, businessAction);
initFrameworkContext(context);
actionContext.setDelayReport(businessAction.isDelayReport());
actionContext.setActionContext(context);
Map<String, Object> applicationContext = Collections.singletonMap(Constants.TCC_ACTION_CONTEXT, context);
String applicationContextStr = JSON.toJSONString(applicationContext);
try {
// 注册分支事务,并返回分支ID
Long branchId = DefaultResourceManager.get().branchRegister(BranchType.TCC, actionName, null, xid, applicationContextStr, null);
return String.valueOf(branchId);
} catch (Throwable t) {
String msg = String.format("TCC branch Register error, xid: %s", xid);
LOGGER.error(msg, t);
throw new FrameworkException(t, msg);
}
}
到此,TC、TM、RM、分支事务都初始化和注册完毕。接下来就是正常执行业务代码,当业务代码执行无异常(即分支事务全部执行成功),则需要进行全局事务提交(回到源码分析开头business.execute成功之后):
private void commitTransaction(GlobalTransaction tx) throws TransactionalExecutor.ExecutionException {
try {
triggerBeforeCommit();
tx.commit();
triggerAfterCommit();
} catch (TransactionException txe) {
// 4.1 Failed to commit
throw new TransactionalExecutor.ExecutionException(tx, txe, TransactionalExecutor.Code.CommitFailure);
}
}
@Override
public void commit() throws TransactionException {
if (role == GlobalTransactionRole.Participant) {
// Participant has no responsibility of committing
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Ignore Commit(): just involved in global transaction [{}]", xid);
}
return;
}
assertXIDNotNull();
int retry = COMMIT_RETRY_COUNT <= 0 ? DEFAULT_TM_COMMIT_RETRY_COUNT : COMMIT_RETRY_COUNT;
try {
while (retry > 0) {
try {
status = transactionManager.commit(xid); // 提交事务
break;
} catch (Throwable ex) {
LOGGER.error("Failed to report global commit [{}],Retry Countdown: {}, reason: {}", this.getXid(), retry, ex.getMessage());
retry--;
if (retry == 0) {
throw new TransactionException("Failed to report global commit", ex);
}
}
}
} finally {
if (xid.equals(RootContext.getXID())) {
suspend();
}
}
if (LOGGER.isInfoEnabled()) {
LOGGER.info("[{}] commit status: {}", xid, status);
}
}
发送请求通知TC服务端全局事务提交:
@Override
public GlobalStatus commit(String xid) throws TransactionException {
GlobalCommitRequest globalCommit = new GlobalCommitRequest();
globalCommit.setXid(xid);
GlobalCommitResponse response = (GlobalCommitResponse) syncCall(globalCommit);
return response.getGlobalStatus();
}
在TC收到全局事务提交的消息后,会发送响应请求告知RM分支事务,执行TCC模式指定的commit方法(RM在AbstractRMHandler.handle方法中处理TC提交分支事务请求):
@Override
public BranchCommitResponse handle(BranchCommitRequest request) {
BranchCommitResponse response = new BranchCommitResponse();
exceptionHandleTemplate(new AbstractCallback<BranchCommitRequest, BranchCommitResponse>() {
@Override
public void execute(BranchCommitRequest request, BranchCommitResponse response) throws TransactionException {
doBranchCommit(request, response); // 分支事务提交
}
}, request, response);
return response;
}
handle方法有两个,有提交、回滚,以上方法是属于提交分支事务方法(回滚方法的逻辑大基本一致,不赘述):
protected void doBranchCommit(BranchCommitRequest request, BranchCommitResponse response) throws TransactionException {
String xid = request.getXid();
long branchId = request.getBranchId();
String resourceId = request.getResourceId();
String applicationData = request.getApplicationData();
if (LOGGER.isInfoEnabled()) {
LOGGER.info("Branch committing: " + xid + " " + branchId + " " + resourceId + " " + applicationData);
}
// 获取资源管理器,并执行分支事务提交方法
BranchStatus status = getResourceManager().branchCommit(request.getBranchType(), xid, branchId, resourceId, applicationData);
response.setXid(xid);
response.setBranchId(branchId);
response.setBranchStatus(status);
if (LOGGER.isInfoEnabled()) {
LOGGER.info("Branch commit result: " + status);
}
}
@Override
public BranchStatus branchCommit(BranchType branchType, String xid, long branchId, String resourceId, String applicationData) throws TransactionException {
TCCResource tccResource = (TCCResource)tccResourceCache.get(resourceId); // 根据资源ID从缓存中获取对应的TCC资源(在TCC模式注册分支时候存入缓存)
if (tccResource == null) {
throw new ShouldNeverHappenException(String.format("TCC resource is not exist, resourceId: %s", resourceId));
}
Object targetTCCBean = tccResource.getTargetBean();
Method commitMethod = tccResource.getCommitMethod(); // 获取TCC资源的commit提交方法
if (targetTCCBean == null || commitMethod == null) {
throw new ShouldNeverHappenException(String.format("TCC resource is not available, resourceId: %s", resourceId));
}
try {
// 获取上下文信息
BusinessActionContext businessActionContext = getBusinessActionContext(xid, branchId, resourceId, applicationData);
Object[] args = this.getTwoPhaseCommitArgs(tccResource, businessActionContext);
Object ret;
boolean result;
// 利用反射机制执行commit方法,完成分支事务的提交
if (Boolean.TRUE.equals(businessActionContext.getActionContext(Constants.USE_TCC_FENCE))) {
try {
result = TCCFenceHandler.commitFence(commitMethod, targetTCCBean, businessActionContext, xid, branchId, args);
} catch (FrameworkException | UndeclaredThrowableException e) {
throw e.getCause();
}
} else {
ret = commitMethod.invoke(targetTCCBean, args);
if (ret != null) {
if (ret instanceof TwoPhaseResult) {
result = ((TwoPhaseResult)ret).isSuccess();
} else {
result = (boolean)ret;
}
} else {
result = true;
}
}
LOGGER.info("TCC resource commit result : {}, xid: {}, branchId: {}, resourceId: {}", result, xid, branchId, resourceId);
return result ? BranchStatus.PhaseTwo_Committed : BranchStatus.PhaseTwo_CommitFailed_Retryable;
} catch (Throwable t) {
String msg = String.format("commit TCC resource error, resourceId: %s, xid: %s.", resourceId, xid);
LOGGER.error(msg, t);
return BranchStatus.PhaseTwo_CommitFailed_Retryable;
}
}
至此结束,以上便是Seata框架的TCC模式源码分析。
因为本文中很多内容在AT模式的源码分析文章已经详细介绍过(例如:TM、RM、TC之间的关系图解,TM、RM客户端的初始化,以及分支事务的数据库相关代理类等等),所以在本文中就不过多赘述,如果想更详细了解相关源码,可以访问本文开头的AT模式文章链接。