当前代码分析基于seata1.6.1
整体描述
整体代码流程可以描述为
- TM开启全局事务,会调用TC来获取XID。
- TC在接收到通知后,会生成XID,然后会将当前全局事务保存到global_table表中,并且返回XID。
- 在获取到XID后,会执行业务逻辑。
- 执行业务逻辑的时候,如果发生了增删改,则会对增删改语句做增强。
- 获取前置镜像数据---执行sql,不提交事务--获取后置镜像---准备undoLog---作为RM向TC提交事务分支---生成undo_log日志---提交本地事务,注意,在这里,本地事务已经提交了。只是有undo_log可用于回滚。
- TC接收RM端提交的分支事务,存储到brand_table中。
- 当全局分支事务都执行完成,TM会向TC提起全局事务提交的请求。
- TC接收到请求后,删除全局事务和分支事务(global_table 和 brand_table)。
- TC 通知RM,删除 undo log 日志。
源码解析
系统启动初始化
主要完成两个事情:初始化 TM和RM客户端;创建方法拦截器
在客户端中,核心配置类是SeataAutoConfiguration,在这个类中初始化了一个核心的扫描器GlobalTransactionScanner。
GlobalTransactionScanner 全局事务扫描器,实现了InitializingBean接口,如果继承了该接口,spring会在完成DI之后,调用afterPropertiesSet方法,在该方法中完成了对TM客户端和RM客户端的创建,代码如下
@Override
public void afterPropertiesSet() {
if (disableGlobalTransaction) {
if (LOGGER.isInfoEnabled()) {
LOGGER.info("Global transaction is disabled.");
}
ConfigurationCache.addConfigListener(ConfigurationKeys.DISABLE_GLOBAL_TRANSACTION,
(ConfigurationChangeListener)this);
return;
}
if (initialized.compareAndSet(false, true)) {
//创建客户端的方法
initClient();
}
}
private void initClient() {
...其他校验
//创建TM客户端并且初始化
TMClient.init(applicationId, txServiceGroup, accessKey, secretKey);
...
//创建RM客户端并且初始化
RMClient.init(applicationId, txServiceGroup);
...
}
同时,GlobalTransactionScanner 继承了AbstractAutoProxyCreator 抽象类,在类完成初始化之后,会调用父类的 postProcessAfterInitialization方法,在父类的方法中,会调用该类重写的一个wrapIfNecessary方法。
wrapIfNecessary 方法会生成一个 GlobalTransactionalInterceptor 全局事务拦截器。
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
// do checkers
if (!doCheckers(bean, beanName)) {
return bean;
}
try {
synchronized (PROXYED_SET) {
if (PROXYED_SET.contains(beanName)) {
return bean;
}
interceptor = null;
//check TCC proxy
if (TCCBeanParserUtils.isTccAutoProxy(bean, beanName, applicationContext)) {
...
} else {
...
//生成一个全局事务处理的拦截器,
if (globalTransactionalInterceptor == nul