Seata 是一款开源的分布式事务解决方案,致力于提供高性能和简单易用的分布式事务服务。
- TC:事务管理器
- TM:事务开始服务
- RM:事务参与过程的其他服务
底层实现流程
- TM和RM都连接到我们的事务协调器TC。
- TM和RM服务的数据源都被Seata代理,执行语句的前后会保存两条记录,一条是执行前的记录,一条是执行后的记录,是方便后期可以逆向的生成sql去回滚事务。具体记录存放在seata的undo_log表中。
- TM在使用RPC-Feign远程调用的时候,在ThreadLocal中获取xid。
- RM在请求头中取到该xid,设置到threadLocal中,同时向seata注册本地事务。
- TM将当前本地事务的结果发送给TC,TC最后通知所有分支事务是提交或回滚。
- TM如果调用接口成功之后再抛出异常时,告诉协调者TC,协调者TC再通知到所有分支的事务,根据undo_log逆向回滚事务。
- 最后如果没有任何异常,TM通知TC,TC最后让所有的有该全局xid的undo_log中的记录都删除。
Seata和LCN的回滚之间有什么区别?
基本实现思路一样,唯一区别在于回滚方式,LCN采用代理数据源加关闭连接,暂时不支持提交本地事务,容易造成数据的死锁。
Seata采用undo_log的形式逆向生成sql,去实现回滚。
Seata生成全局ID源码部分
核心注解在于@GlobalTransactional
引入seata核心依赖
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-seata</artifactId>
<version>2.1.1.RELEASE</version>
</dependency>
先看到spring.factories配置文件
看到com.alibaba.cloud.seata.GlobalTransactionAutoConfiguration,
这个类
点进去,可以看到,这就是初始化seata的一个配置类。
并且注入全局事务扫描器,如下代码
@Bean
public GlobalTransactionScanner globalTransactionScanner() {
String applicationName = applicationContext.getEnvironment()
.getProperty("spring.application.name");
String txServiceGroup = seataProperties.getTxServiceGroup();
if (StringUtils.isEmpty(txServiceGroup)) {
txServiceGroup = applicationName + "-seata-service-group";
seataProperties.setTxServiceGroup(txServiceGroup);
}
return new GlobalTransactionScanner(applicationName, txServiceGroup);
}
点到全局事务扫描类中
public class GlobalTransactionScanner extends AbstractAutoProxyCreator
implements InitializingBean, ApplicationContextAware,
DisposableBean
可以看到全局事务扫描类继承/实现了以下的接口,那么分别是做啥用的呢?
首先我们根据SpringBean和Aop的源码不难发现
AbstractAutoProxyCreator就是Aop原生的一个代理类
而InitializingBean属于Spring的Bean中的一个注解,执行动作在Bean实例化之后执行。
因此对于这个接口的回调方法中,就实现初始化的动作
源码如下
@Override
public void afterPropertiesSet() {
if (disableGlobalTransaction) {
if (LOGGER.isInfoEnabled()) {
LOGGER.info("Global transaction is disabled.");
}
return;
}
initClient();
}
private void initClient() {
if (LOGGER.isInfoEnabled()) {
LOGGER.info("Initializing Global Transaction Clients ... ");
}
if (StringUtils.isNullOrEmpty(applicationId) || StringUtils.isNullOrEmpty(txServiceGroup)) {
throw new IllegalArgumentException(
"applicationId: " + applicationId + ", txServiceGroup: " + txServiceGroup);
}
//init TM
TMClient.init(applicationId, txServiceGroup);
if (LOGGER.isInfoEnabled()) {
LOGGER.info(
"Transaction Manager Client is initialized. applicationId[" + applicationId + "] txServiceGroup["
+ txServiceGroup + "]");
}
//init RM
RMClient.init(applicationId, txServiceGroup);
if (LOGGER.isInfoEnabled()) {
LOGGER.info(
"Resource Manager is initialized. applicationId[" + applicationId + "] txServiceGroup[" + txServiceGroup
+ "]");
}
if (LOGGER.isInfoEnabled()) {
LOGGER.info("Global Transaction Clients are initialized. ");
}
registerSpringShutdownHook();
}
然后看到可以发现这两行代码
//init TM
TMClient.init(applicationId, txServiceGroup);
//init RM
RMClient.init(applicationId, txServiceGroup);
可以看到,在初始化方法中,就实现了初始化RM、TM然后,注册到TC中。
然后AbstractAutoProxyCreator这个抽象模板又是拿来干啥的呢?
对比下抽象类和这个实现类可以看到,主要是
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey)
重写了父类的这个回调方法。
看到实现类这个方法,
其作用就是,加上@GlobalTransactional这个注解后,当aop创建代理对象的时候,会走这个回调方法,去创建出GlobalTransactionalInterceptor对象。
点进去这个对象发现,哎,实现了MethodInterceptor接口,说明其采用CGLIB代理模式,进行代理,从而进行方法的反射。
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);
final Method method = BridgeMethodResolver.findBridgedMethod(specificMethod);
final GlobalTransactional globalTransactionalAnnotation = getAnnotation(method, GlobalTransactional.class);
final GlobalLock globalLockAnnotation = getAnnotation(method, GlobalLock.class);
if (globalTransactionalAnnotation != null) {
return handleGlobalTransaction(methodInvocation, globalTransactionalAnnotation);
} else if (globalLockAnnotation != null) {
return handleGlobalLock(methodInvocation);
} else {
return methodInvocation.proceed();
}
}
其中获取到两个注解
- GlobalTransactional,判断你方法上有没有加上这个全局事务的注解
- GlobalLock,作为分布式锁
因此直接点到handleGlobalTransaction()方法中
查看return transactionalTemplate.execute()这个execute方法
具体源码如下
public Object execute(TransactionalExecutor business) throws Throwable {
// 1. get or create a transaction