SpringCloud Alibaba系列——17Seata AT模式源码分析(下)
作者 | 一起撸Java
来源 |今日头条
2.4 AbstractAutoProxyCreator
GlobalTransactionScanner初始化完了TM和RM以后,我们再关注一下AbstractAutoProxyCreator,自动代理。
自动代理,它代理啥东西呢?或者说它给spring中的Bean增强了什么功能?
GlobalTransactionScanner主要扩展了AbstractAutoProxyCreator的wrapIfNecessary
代理增强的前置判断处理,表示是否该Bean需要增强,如果增强的话创建代理类
2.4.1 wrapIfNecessary
@Overrideprotected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) { if (disableGlobalTransaction) { return bean; } try { synchronized (PROXYED_SET) { // 相同Bean排重 if (PROXYED_SET.contains(beanName)) { return bean; } interceptor = null; // 判断是否开启TCC模式 if (TCCBeanParserUtils.isTccAutoProxy(bean, beanName, applicationContext)) { // TCC实现的拦截器 interceptor = new TccActionInterceptor(TCCBeanParserUtils.getRemotingDesc(beanName)); } else { Class<?> serviceInterface = SpringProxyUtils.findTargetClass(bean); Class<?>[] interfacesIfJdk = SpringProxyUtils.findInterfaces(bean); // 判断是否存在@GlobalTransactional或者@GlobalLock注解 if (!existsAnnotation(new Class[]{serviceInterface}) && !existsAnnotation(interfacesIfJdk)) { return bean; } if (interceptor == null) { // 非TCC的拦截器 if (globalTransactionalInterceptor == null) { globalTransactionalInterceptor = new GlobalTransactionalInterceptor(failureHandlerHook); ConfigurationCache.addConfigListener( ConfigurationKeys.DISABLE_GLOBAL_TRANSACTION, (ConfigurationChangeListener)globalTransactionalInterceptor); } interceptor = globalTransactionalInterceptor; } } // 判断当前Bean是否已经是spring的代理类了 if (!AopUtils.isAopProxy(bean)) { // 如果还不是,那么走一轮spring的代理过程即可 bean = super.wrapIfNecessary(bean, beanName, cacheKey); } else { // 如果是一个spring的代理类,那么反射获取代理类中已经存在的拦截器集合,然后添加到该集合当中 AdvisedSupport advised = SpringProxyUtils.getAdvisedSupport(bean); Advisor[] advisor = buildAdvisors(beanName, getAdvicesAndAdvisorsForBean(null, null, null)); for (Advisor avr : advisor) { advised.addAdvisor(0, avr); } } PROXYED_SET.add(beanName); return bean; } } catch (Exception exx) {}}
wrapIfNecessary方法较长我们分步骤看看
1)isTccAutoProxy判断是否开启tcc模式,开启的话选择了TccActionInterceptor拦截器,非tcc模式选择
GlobalTransactionalInterceptor拦截器,默认不开启
2)existAnnotation判断当前Bean是否有类或者接口的方法存在@GlobalTransactional或者@GlobalLock注解,如果没有则直接返回
3)isAopProxy方法是判断当前的Bean是否已经是spring的代理类了,无论是JDK动态代理还是Cglib类代理。如果是普通的Bean,走原有的生成代理逻辑即可,如果已经是代理类,那么要通过反射获取代理对象内的拦截器集合也叫做Advisor,直接添加到该集合当中。
wrapIfNecessary的方法并不复杂,但是如果对代理不是很熟悉或许对细节点会有些困惑。
2.4.1.1 AT一阶段开启全局事务
在需要进行全局事务管理的接口上,会加@GlobalTransactional注解,这个注解会又一个对应的拦截器进行拦截
GlobalTransactionalInterceptor,invoke就是拦截方法
@Overridepublic 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); //获取方法上的全局锁注解 final GlobalLock globalLockAnnotation = getAnnotation(method, targetClass, GlobalLock.class); boolean localDisable = disable || (degradeCheck && degradeNum >= degradeCheckAllowTimes); if (!localDisable) { //如果方法上有全局事务注解,调用handleGlobalTransaction开启全局事务 if (globalTransactionalAnnotation != null) { return handleGlobalTransaction(methodInvocation, globalTransactionalAnnotation); //如果方法上有全局锁注解,调用handleGlobalLock开启全局锁 } else if (globalLockAnnotation != null) { return handleGlobalLock(methodInvocation); } } } //如果啥都没有,按普通方法执行,提升性能 return methodInvocation.proceed();}
在handleGlobalTransaction方法中调用了
transactionalTemplate.execute方法
// 2. 开启全局事务beginTransactionbeginTransaction(txInfo, tx); Object rs = null;try { // 执行业务方法business.execute() rs = business.execute(); } catch (Throwable ex) { // 3.出现异常执行completeTransactionAfterThrowing回滚 completeTransactionAfterThrowing(txInfo, tx, ex); throw ex;} // 4. 没有异常提交事务commitTransactioncommitTransaction(tx);
开启全局事务最终调用
io.seata.tm.api.DefaultGlobalTransaction#begin(int, java.lang.String)方法
@Overridepublic void begin(int timeout, String name) throws TransactionException { //此处的角色判断有关键的作用//表明当前是全局事务的发起者(Launcher)还是参与者(Participant)//如果在分布式事务的下游系统方法中也加上GlobalTransactional注解//那么它的角色就是Participant,即会忽略后面的begin就退出了 //而判断是发起者(Launcher)还是参与者(Participant)是根据当前上下文是否已存在XID来判断 //没有XID的就是Launcher,已经存在XID的就是Participant if (role != GlobalTransactionRole.Launcher) { assertXIDNotNull(); if (LOGGER.isDebugEnabled()) { LOGGER.debug("Ignore Begin(): just involved in global transaction [{}]", xid); } return; } assertXIDNull(); if (RootContext.getXID() != null) { throw new IllegalStateException(); } xid = transactionManager.begin(null, null, name, timeout); status = GlobalStatus.Begin; RootContext.bind(xid); if (LOGGER.isInfoEnabled()) { LOGGER.info("Begin new global transaction [{}]", xid); } }
请求seata-server获取全局事务XID
@Overridepublic String begin(String applicationId, String transactionServiceGroup, String name, int timeout) throws TransactionException { GlobalBeginRequest request = new GlobalBeginRequest(); request.setTransactionName(name); request.setTimeout(timeout); //跟进 GlobalBeginResponse response = (GlobalBeginResponse) syncCall(request); if (response.getResultCode() == ResultCode.Failed) { throw new TmTransactionException(TransactionExceptionCode.BeginFailed, response.getMsg()); } return response.getXid();}
private AbstractTransactionResponse syncCall(AbstractTransactionRequest request) throws TransactionException { try { //TMClient封装的Netty对象 return (AbstractTransactionResponse) TmNettyRemotingClient.getInstance().sendSyncRequest(request); } catch (TimeoutException toe) { throw new TmTransactionException(TransactionExceptionCode.IO, "RPC timeout", toe); }}
将XID绑定在RootContext中,由此可以看出全局事务是由TM发起的,TM发起全局事务请求给seata-server服务,seata-server服务接受到请求后处理(以下是seata服务代码):
@Overrideprotected void doGlobalBegin(GlobalBeginRequest request, GlobalBeginResponse response, RpcContext rpcContext) throws TransactionException { //进入begin response.setXid(core.begin(rpcContext.getApplicationId(), rpcContext.getTransactionServiceGroup(), request.getTransactionName(), request.getTimeout())); if (LOGGER.isInfoEnabled()) { LOGGER.info("Begin new global transaction applicationId: {},transactionServiceGroup: {}, transactionName: {},timeout:{},xid:{}", rpcContext.getApplicationId(), rpcContext.getTransactionServiceGroup(), request.getTransactionName(), request.getTimeout(), response.getXid()); }}
io.seata.server.coordinator.DefaultCoordinator#doGlobalBegin方法接受客户端开启全局事务的请求,调用io.seata.server.coordinator.DefaultCore#begin开启全局事务
@Overridepublic String begin(String applicationId, String transactionServiceGroup, String name, int timeout) throws TransactionException { GlobalSession session = GlobalSession.createGlobalSession(applicationId, transactionServiceGroup, name, timeout); MDC.put(RootContext.MDC_KEY_XID, session.getXid()); session.addSessionLifecycleListener(SessionHolder.getRootSessionManager());//开启会话 session.begin(); // transaction start event eventBus.post(new GlobalTransactionEvent(session.getTransactionId(), GlobalTransactionEvent.ROLE_TC, session.getTransactionName(), applicationId, transactionServiceGroup, session.getBeginTime(), null, session.getStatus())); return session.getXid();}
通过当前会话开启
@Overridepublic void begin() throws TransactionException { this.status = GlobalStatus.Begin; this.beginTime = System.currentTimeMillis(); this.active = true; for (SessionLifecycleListener lifecycleListener : lifecycleListeners) { lifecycleListener.onBegin(this); }}
调用
io.seata.server.session.AbstractSessionManager#onBegin方法,又调用io.seata.server.storage.db.session.DataBaseSessionManager#addGlobalSession方法
@Overridepublic void addGlobalSession(GlobalSession session) throws TransactionException { if (StringUtils.isBlank(taskName)) { //进入 boolean ret = transactionStoreManager.writeSession(LogOperation.GLOBAL_ADD, session); if (!ret) { throw new StoreException("addGlobalSession failed."); } } else { boolean ret = transactionStoreManager.writeSession(LogOperation.GLOBAL_UPDATE, session); if (!ret) { throw new StoreException("addGlobalSession failed."); } }}
这里往数据库里写入数据
@Overridepublic boolean writeSession(LogOperation logOperation, SessionStorable session) { if (LogOperation.GLOBAL_ADD.equals(logOperation)) { return logStore.insertGlobalTransactionDO(SessionConverter.convertGlobalTransactionDO(session)); } else if (LogOperation.GLOBAL_UPDATE.equals(logOperation)) { return logStore.updateGlobalTransactionDO(SessionConverter.convertGlobalTransactionDO(session)); } else if (LogOperation.GLOBAL_REMOVE.equals(logOperation)) { return logStore.deleteGlobalTransactionDO(SessionConverter.convertGlobalTransactionDO(session)); } else if (LogOperation.BRANCH_ADD.equals(logOperation)) { return logStore.insertBranchTransactionDO(SessionConverter.convertBranchTransactionDO(session)); } else if (LogOperation.BRANCH_UPDATE.equals(logOperation)) { return logStore.updateBranchTransactionDO(SessionConverter.convertBranchTransactionDO(session)); } else if (LogOperation.BRANCH_REMOVE.equals(logOperation)) { return logStore.deleteBranchTransactionDO(SessionConverter.convertBranchTransactionDO(session)); } else { throw new StoreException("Unknown LogOperation:" + logOperation.name()); }}
这里向seata库global_tab插入数据,到此全局事务已开启
2.4.1.2 AT一阶段执行业务SQL
全局事务已开启,下面需要执行业务SQL,生成undo_log数据,全局事务拦截成功后最终还是执行了业务方法的,但是由于Seata对数据源做了代理,所以sql解析与undo_log入库操作是在数据源代理中执行的,代理就是Seata对DataSource,Connection,Statement做的代理封装类
/*** 构造datasource代理对象,替换原来的的datasource*/@Primary@Bean("dataSource")public DataSourceProxy dataSourceProxy(DataSource druidDataSource){ return new DataSourceProxy(druidDataSource);}
项目中使用的数据源均用seata的DataSourceProxy代替最终对Sql进行解析操作,发生在StatementProxy类中
@Overridepublic boolean execute(String sql) throws SQLException { this.targetSQL = sql; return ExecuteTemplate.execute(this, (statement, args) -> statement.execute((String) args[0]), sql);}
public static <T, S extends Statement> T execute(List<SQLRecognizer> sqlRecognizers, StatementProxy<S> statementProxy, StatementCallback<T, S> statementCallback, Object... args) throws SQLException { if (!RootContext.requireGlobalLock() && !StringUtils.equals(BranchType.AT.name(), RootContext.getBranchType())) { //不是全局事务的直接执行,提升性能 return statementCallback.execute(statementProxy.getTargetStatement(), args); } String dbType = statementProxy.getConnectionProxy().getDbType(); if (CollectionUtils.isEmpty(sqlRecognizers)) { sqlRecognizers = SQLVisitorFactory.get( statementProxy.getTargetSQL(), dbType); } Executor<T> executor; if (CollectionUtils.isEmpty(sqlRecognizers)) { executor = new PlainExecutor<>(statementProxy, statementCallback); } else { if (sqlRecognizers.size() == 1) { SQLRecognizer sqlRecognizer = sqlRecognizers.get(0); //不同SQL类型,不同处理 switch (sqlRecognizer.getSQLType()) { case INSERT: executor = EnhancedServiceLoader.load(InsertExecutor.class, dbType, new Class[]{StatementProxy.class, StatementCallback.class, SQLRecognizer.class}, new Object[]{statementProxy, statementCallback, sqlRecognizer}); break; case UPDATE: executor = new UpdateExecutor<>(statementProxy, statementCallback, sqlRecognizer); break; case DELETE: executor = new DeleteExecutor<>(statementProxy, statementCallback, sqlRecognizer); break; case SELECT_FOR_UPDATE: executor = new SelectForUpdateExecutor<>(statementProxy, statementCallback, sqlRecognizer); break; default: executor = new PlainExecutor<>(statementProxy, statementCallback); break; } } else { executor = new MultiExecutor<>(statementProxy, statementCallback, sqlRecognizers); } } T rs; try { //执行SQL rs = executor.execute(args); } catch (Throwable ex) { if (!(ex instanceof SQLException)) { // Turn other exception into SQLException ex = new SQLException(ex); } throw (SQLException) ex; } return rs; }
- 先判断是否开启了全局事务,如果没有,不走代理,不解析sql,提升性能
- 调用SQLVisitorFactory对目标sql进行解析
- 针对特定类型sql操作(INSERT,UPDATE,DELETE,SELECT_FOR_UPDATE)等进行特殊解析
- 执行sql并返回结果
不同类型的SQL处理方法不一样,这里以insert为例
insert使用的是InsertExecutor.execute方法,但其实最终还是使用
io.seata.rm.datasource.exec.BaseTransactionalExecutor#execute方法
@Overridepublic T execute(Object... args) throws Throwable { if (RootContext.inGlobalTransaction()) { String xid = RootContext.getXID(); statementProxy.getConnectionProxy().bind(xid); } statementProxy.getConnectionProxy().setGlobalLockRequire(RootContext.requireGlobalLock()); return doExecute(args);}
将上下文中的xid绑定到了statementProxy中,并调用了doExecute方法,看下AbstractDMLBaseExecutor中的doExecute方法
@Overridepublic T doExecute(Object... args) throws Throwable { AbstractConnectionProxy connectionProxy = statementProxy.getConnectionProxy(); if (connectionProxy.getAutoCommit()) { return executeAutoCommitTrue(args); } else { return executeAutoCommitFalse(args); }}
方法中调用了
executeAutoCommitTrue/executeAutoCommitFalse
protected T executeAutoCommitTrue(Object[] args) throws Throwable { ConnectionProxy connectionProxy = statementProxy.getConnectionProxy(); try { connectionProxy.setAutoCommit(false); return new LockRetryPolicy(connectionProxy).execute(() -> { T result = executeAutoCommitFalse(args); connectionProxy.commit(); return result; }); } catch (Exception e) { ... } finally { connectionProxy.getContext().reset(); connectionProxy.setAutoCommit(true); }}
但仔细发现,最终都是调用executeAutoCommitFalse方法
protected T executeAutoCommitFalse(Object[] args) throws Exception { //跟入getTableMeta方法 if (!JdbcConstants.MYSQL.equalsIgnoreCase(getDbType()) && getTableMeta().getPrimaryKeyOnlyName().size() > 1) { throw new NotSupportYetException("multi pk only support mysql!"); } //获取beforeImage TableRecords beforeImage = beforeImage(); //执行业务sql T result = statementCallback.execute(statementProxy.getTargetStatement(), args); //获取afterImage TableRecords afterImage = afterImage(beforeImage); //保存image prepareUndoLog(beforeImage, afterImage); return result;}
获取beforeImage
//tableMeta里面包含表名、列、索引等数据protected TableMeta getTableMeta(String tableName) { if (tableMeta != null) { return tableMeta; } ConnectionProxy connectionProxy = statementProxy.getConnectionProxy(); tableMeta = TableMetaCacheFactory.getTableMetaCache(connectionProxy.getDbType()) .getTableMeta(connectionProxy.getTargetConnection(), tableName, connectionProxy.getDataSourceProxy().getResourceId()); return tableMeta;}
执行业务sql还是使用
com.alibaba.druid.pool.DruidPooledPreparedStatement#execute方法执行
获取afterImage在提交事务时,插入undo_log日志
protected T executeAutoCommitTrue(Object[] args) throws Throwable { ConnectionProxy connectionProxy = statementProxy.getConnectionProxy(); try { connectionProxy.setAutoCommit(false); return new LockRetryPolicy(connectionProxy).execute(() -> { T result = executeAutoCommitFalse(args); //跟入 connectionProxy.commit(); return result; }); } catch (Exception e) { ... } finally { connectionProxy.getContext().reset(); connectionProxy.setAutoCommit(true); }}
public void commit() throws SQLException { try { LOCK_RETRY_POLICY.execute(() -> { //跟入 doCommit(); return null; }); } catch (SQLException e) { throw e; } catch (Exception e) { throw new SQLException(e); }}
private void doCommit() throws SQLException { if (context.inGlobalTransaction()) { //跟入 processGlobalTransactionCommit(); } else if (context.isGlobalLockRequire()) { processLocalCommitWithGlobalLocks(); } else { targetConnection.commit(); }}
private void processGlobalTransactionCommit() throws SQLException { try { //向seata-server注册分支信息 register(); } catch (TransactionException e) { recognizeLockKeyConflictException(e, context.buildLockKeys()); } try { //提交事务之前,插入undo_log,跟入flushUndoLogs UndoLogManagerFactory.getUndoLogManager(this.getDbType()).flushUndoLogs(this); targetConnection.commit(); } catch (Throwable ex) { ... } if (IS_REPORT_SUCCESS_ENABLE) { report(true); } context.reset();}
public void flushUndoLogs(ConnectionProxy cp) throws SQLException { ConnectionContext connectionContext = cp.getContext(); if (!connectionContext.hasUndoLog()) { return; } String xid = connectionContext.getXid(); long branchId = connectionContext.getBranchId(); ...//该方法插入undo_log insertUndoLogWithNormal(xid, branchId, buildContext(parser.getName()), undoLogContent, cp.getTargetConnection());}
在该方法中注册分支事务提交事务,向seata-server注册分支信息,seata-server接收到请求(seata源码)
io.seata.server.coordinator.DefaultCoordinator#doBranchRegister方法
public Long branchRegister(BranchType branchType, String resourceId, String clientId, String xid, String applicationData, String lockKeys) throws TransactionException { GlobalSession globalSession = assertGlobalSessionNotNull(xid, false); return SessionHolder.lockAndExecute(globalSession, () -> { ... try { //进行注册 globalSession.addBranch(branchSession); } catch (RuntimeException ex) { ... } ... return branchSession.getBranchId(); });}
@Overridepublic void addBranch(BranchSession branchSession) throws TransactionException { for (SessionLifecycleListener lifecycleListener : lifecycleListeners) { //跟入onAddBranch,选择AbstractSessionManager lifecycleListener.onAddBranch(this, branchSession); } branchSession.setStatus(BranchStatus.Registered); add(branchSession);}
io.seata.server.storage.db.session.DataBaseSessionManager#addBranchSession方法
@Overridepublic void onAddBranch(GlobalSession globalSession, BranchSession branchSession) throws TransactionException { //跟入,选择DataBaseSessionManager addBranchSession(globalSession, branchSession);}
@Overridepublic void addBranchSession(GlobalSession globalSession, BranchSession session) throws TransactionException { if (StringUtils.isNotBlank(taskName)) { return; } //跟入 boolean ret = transactionStoreManager.writeSession(LogOperation.BRANCH_ADD, session); if (!ret) { throw new StoreException("addBranchSession failed."); }}
@Overridepublic boolean writeSession(LogOperation logOperation, SessionStorable session) { if (LogOperation.GLOBAL_ADD.equals(logOperation)) { return logStore.insertGlobalTransactionDO(SessionConverter.convertGlobalTransactionDO(session)); } else if (LogOperation.GLOBAL_UPDATE.equals(logOperation)) { return logStore.updateGlobalTransactionDO(SessionConverter.convertGlobalTransactionDO(session)); } else if (LogOperation.GLOBAL_REMOVE.equals(logOperation)) { return logStore.deleteGlobalTransactionDO(SessionConverter.convertGlobalTransactionDO(session)); } else if (LogOperation.BRANCH_ADD.equals(logOperation)) { return logStore.insertBranchTransactionDO(SessionConverter.convertBranchTransactionDO(session)); } else if (LogOperation.BRANCH_UPDATE.equals(logOperation)) { return logStore.updateBranchTransactionDO(SessionConverter.convertBranchTransactionDO(session)); } else if (LogOperation.BRANCH_REMOVE.equals(logOperation)) { return logStore.deleteBranchTransactionDO(SessionConverter.convertBranchTransactionDO(session)); } else { throw new StoreException("Unknown LogOperation:" + logOperation.name()); }}
@Overridepublic boolean insertBranchTransactionDO(BranchTransactionDO branchTransactionDO) { String sql = LogStoreSqlsFactory.getLogStoreSqls(dbType).getInsertBranchTransactionSQL(branchTable); Connection conn = null; PreparedStatement ps = null; try { int index = 1; conn = logStoreDataSource.getConnection(); conn.setAutoCommit(true); ps = conn.prepareStatement(sql); ps.setString(index++, branchTransactionDO.getXid()); ps.setLong(index++, branchTransactionDO.getTransactionId()); ps.setLong(index++, branchTransactionDO.getBranchId()); ps.setString(index++, branchTransactionDO.getResourceGroupId()); ps.setString(index++, branchTransactionDO.getResourceId()); ps.setString(index++, branchTransactionDO.getBranchType()); ps.setInt(index++, branchTransactionDO.getStatus()); ps.setString(index++, branchTransactionDO.getClientId()); ps.setString(index++, branchTransactionDO.getApplicationData()); return ps.executeUpdate() > 0; } catch (SQLException e) { throw new StoreException(e); } finally { IOUtil.close(ps, conn); }}
Seata-server添加分支信息完成,到这里,一阶段结束,业务数据,undo_log,分支信息都已经写入数据库
2.4.1.3 AT二阶段提交
回到handleGlobalTransaction方法中,调用了
transactionalTemplate.execute方法
// 2. 开启全局事务beginTransactionbeginTransaction(txInfo, tx); Object rs = null;try { // 执行业务方法business.execute() rs = business.execute(); } catch (Throwable ex) { //上面是一阶段 //下面是二阶段 // 3.出现异常执行completeTransactionAfterThrowing回滚 completeTransactionAfterThrowing(txInfo, tx, ex); throw ex;} // 4. 没有异常提交事务commitTransactioncommitTransaction(tx);
二阶段提交
commitTransaction(tx);跟进
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); }}
@Overridepublic GlobalStatus commit(String xid) throws TransactionException { GlobalCommitRequest globalCommit = new GlobalCommitRequest(); globalCommit.setXid(xid); //跟入syncCall GlobalCommitResponse response = (GlobalCommitResponse) syncCall(globalCommit); return response.getGlobalStatus();}
private AbstractTransactionResponse syncCall(AbstractTransactionRequest request) throws TransactionException { try { return (AbstractTransactionResponse) TmNettyRemotingClient.getInstance().sendSyncRequest(request); } catch (TimeoutException toe) { throw new TmTransactionException(TransactionExceptionCode.IO, "RPC timeout", toe); }}
最终通过TM请求seata-server,Seata-server接收到全局提交请求(seata源码)
DefaultCoordinator中
@Overrideprotected void doGlobalCommit(GlobalCommitRequest request, GlobalCommitResponse response, RpcContext rpcContext) throws TransactionException { MDC.put(RootContext.MDC_KEY_XID, request.getXid()); //跟入commit response.setGlobalStatus(core.commit(request.getXid()));}
Seata-server接收到客户端全局提交请求后,先回调客户端,删除undo_log,seata在删除分支及全局事务
之前说过RMClient在初始化时,设置资源管理器resourceManager,设置消息回调监听器用于接收TC在二阶段发出的提交或者回滚请求Seata-server删除分支数据及全局事务数据
@Overridepublic void removeBranch(BranchSession branchSession) throws TransactionException { // do not unlock if global status in (Committing, CommitRetrying, AsyncCommitting), // because it's already unlocked in 'DefaultCore.commit()' if (status != Committing && status != CommitRetrying && status != AsyncCommitting) { if (!branchSession.unlock()) { throw new TransactionException("Unlock branch lock failed, xid = " + this.xid + ", branchId = " + branchSession.getBranchId()); } } for (SessionLifecycleListener lifecycleListener : lifecycleListeners) { //跟入 lifecycleListener.onRemoveBranch(this, branchSession); } remove(branchSession);}
private void writeSession(LogOperation logOperation, SessionStorable sessionStorable) throws TransactionException { if (!transactionStoreManager.writeSession(logOperation, sessionStorable)) { if (LogOperation.GLOBAL_ADD.equals(logOperation)) { throw new GlobalTransactionException(TransactionExceptionCode.FailedWriteSession, "Fail to store global session"); } else if (LogOperation.GLOBAL_UPDATE.equals(logOperation)) { throw new GlobalTransactionException(TransactionExceptionCode.FailedWriteSession, "Fail to update global session"); } else if (LogOperation.GLOBAL_REMOVE.equals(logOperation)) { throw new GlobalTransactionException(TransactionExceptionCode.FailedWriteSession, "Fail to remove global session"); } else if (LogOperation.BRANCH_ADD.equals(logOperation)) { throw new BranchTransactionException(TransactionExceptionCode.FailedWriteSession, "Fail to store branch session"); } else if (LogOperation.BRANCH_UPDATE.equals(logOperation)) { throw new BranchTransactionException(TransactionExceptionCode.FailedWriteSession, "Fail to update branch session"); } else if (LogOperation.BRANCH_REMOVE.equals(logOperation)) { throw new BranchTransactionException(TransactionExceptionCode.FailedWriteSession, "Fail to remove branch session"); } else { throw new BranchTransactionException(TransactionExceptionCode.FailedWriteSession, "Unknown LogOperation:" + logOperation.name()); } }}
public static void endCommitted(GlobalSession globalSession) throws TransactionException { globalSession.changeStatus(GlobalStatus.Committed); //删除全局事务 globalSession.end();}
客户端删除undo_log数据
在接收提交里面
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); } }
getResourceManager获取的就是RMClient初始化时设置的资源管理器DataSourceManager
public BranchStatus branchCommit(BranchType branchType, String xid, long branchId, String resourceId, String applicationData) throws TransactionException { return asyncWorker.branchCommit(branchType, xid, branchId, resourceId, applicationData);}
@Overridepublic BranchStatus branchCommit(BranchType branchType, String xid, long branchId, String resourceId, String applicationData) throws TransactionException { if (!ASYNC_COMMIT_BUFFER.offer(new Phase2Context(branchType, xid, branchId, resourceId, applicationData))) { LOGGER.warn("Async commit buffer is FULL. Rejected branch [{}/{}] will be handled by housekeeping later.", branchId, xid); } return BranchStatus.PhaseTwo_Committed;}
这边只是往一个ASYNC_COMMIT_BUFFER缓冲List中新增了一个二阶段提交的context,但真正提交在AsyncWorker的init()方法
public synchronized void init() { LOGGER.info("Async Commit Buffer Limit: {}", ASYNC_COMMIT_BUFFER_LIMIT); ScheduledExecutorService timerExecutor = new ScheduledThreadPoolExecutor(1, new NamedThreadFactory("AsyncWorker", 1, true)); timerExecutor.scheduleAtFixedRate(() -> { try {//跟入 doBranchCommits(); } catch (Throwable e) { LOGGER.info("Failed at async committing ... {}", e.getMessage()); } }, 10, 1000 * 1, TimeUnit.MILLISECONDS);}
删除Undo_log
二阶段回滚
二阶段回滚seata-server端代码与二阶段提交类似,这里省略
protected void doGlobalRollback(GlobalRollbackRequest request, GlobalRollbackResponse response, RpcContext rpcContext) throws TransactionException { MDC.put(RootContext.MDC_KEY_XID, request.getXid()); //全局回滚sea他接收请求 response.setGlobalStatus(core.rollback(request.getXid()));}
主要看回滚客户端如何进行事务补偿
@Overridepublic BranchRollbackResponse handle(BranchRollbackRequest request) { BranchRollbackResponse response = new BranchRollbackResponse(); exceptionHandleTemplate(new AbstractCallback<BranchRollbackRequest, BranchRollbackResponse>() { @Override public void execute(BranchRollbackRequest request, BranchRollbackResponse response) throws TransactionException { //跟入 doBranchRollback(request, response); } }, request, response); return response;}
public BranchStatus branchRollback(BranchType branchType, String xid, long branchId, String resourceId, String applicationData) throws TransactionException { DataSourceProxy dataSourceProxy = get(resourceId); if (dataSourceProxy == null) { throw new ShouldNeverHappenException(); } try { UndoLogManagerFactory.getUndoLogManager(dataSourceProxy.getDbType()).undo(dataSourceProxy, xid, branchId); } catch (TransactionException te) { StackTraceLogger.info(LOGGER, te, "branchRollback failed. branchType:[{}], xid:[{}], branchId:[{}], resourceId:[{}], applicationData:[{}]. reason:[{}]", new Object[]{branchType, xid, branchId, resourceId, applicationData, te.getMessage()}); if (te.getCode() == TransactionExceptionCode.BranchRollbackFailed_Unretriable) { return BranchStatus.PhaseTwo_RollbackFailed_Unretryable; } else { return BranchStatus.PhaseTwo_RollbackFailed_Retryable; } } return BranchStatus.PhaseTwo_Rollbacked; }
最终回滚方法调用的是UndoLogManager.undo(dataSourceProxy, xid, branchId);判断undolog是否存在,存在则删除对应undolog,并一起提交,到此seata的AT模式源码解析完毕。