官方文档:http://seata.io/zh-cn/docs/overview/what-is-seata.html
1、Seata流程概述
参考 http://www.dreamwu.com/post-1741.html
2、SpringCloud+Eureka+Seata1.4.2 整合
参考 https://www.jianshu.com/p/90b0995d57bb
3、源码流程解读
打开 SeataAutoConfiguration,代码不多,都是关键代码
38行的 @ConditionalOnProperty 指定bean注册的环境,只有在seata.enabled为true时。若找不到这个属性默认为true
接下来的 failureHandler,当没有自定义实现时,会返回一个默认的实现。
然后就是globalTransactionScanner,看名字就知道跟全局事务有关联。看源码。
AbstractAutoProxyCreator 对使用全局事务注解的bean动态代理
实现InitialzingBean afterPropertiesSet初始化
实现ApplicationContextAware对ApplicationContext操作
ConfigurationChangeListener 配置修改监听器,实现注册配置订阅事件监听器和配置中心动态订阅功能与适配。
代理方法 wrapIfNecessary里面交给 GlobalTransactionalInterceptor 接管
在invoke方法里,对使用了GlobalTransactional和GlobalLock的bean进行代理,handleGlobalTransaction和handleGlobalLock两个方法。
handleGlobalTransaction直接调用事务模板类template的execute方法。
Object handleGlobalTransaction(final MethodInvocation methodInvocation,
final GlobalTransactional globalTrxAnno) throws Throwable {
boolean succeed = true;
try {
return transactionalTemplate.execute(new TransactionalExecutor() {
@Override
public Object execute() throws Throwable {
return methodInvocation.proceed();
}
public String name() {
String name = globalTrxAnno.name();
if (!StringUtils.isNullOrEmpty(name)) {
return name;
}
return formatMethod(methodInvocation.getMethod());
}
@Override
public TransactionInfo getTransactionInfo() {
// reset the value of timeout
int timeout = globalTrxAnno.timeoutMills();
if (timeout <= 0 || timeout == DEFAULT_GLOBAL_TRANSACTION_TIMEOUT) {
timeout = defaultGlobalTransactionTimeout;
}
TransactionInfo transactionInfo = new TransactionInfo();
transactionInfo.setTimeOut(timeout);
transactionInfo.setName(name());
transactionInfo.setPropagation(globalTrxAnno.propagation());
transactionInfo.setLockRetryInternal(globalTrxAnno.lockRetryInternal());
transactionInfo.setLockRetryTimes(globalTrxAnno.lockRetryTimes());
Set<RollbackRule> rollbackRules = new LinkedHashSet<>();
for (Class<?> rbRule : globalTrxAnno.rollbackFor()) {
rollbackRules.add(new RollbackRule(rbRule));
}
for (String rbRule : globalTrxAnno.rollbackForClassName()) {
rollbackRules.add(new RollbackRule(rbRule));
}
for (Class<?> rbRule : globalTrxAnno.noRollbackFor()) {
rollbackRules.add(new NoRollbackRule(rbRule));
}
for (String rbRule : globalTrxAnno.noRollbackForClassName()) {
rollbackRules.add(new NoRollbackRule(rbRule));
}
transactionInfo.setRollbackRules(rollbackRules);
return transactionInfo;
}
});
} catch (TransactionalExecutor.ExecutionException e) {
TransactionalExecutor.Code code = e.getCode();
switch (code) {
case RollbackDone:
throw e.getOriginalException();
case BeginFailure:
succeed = false;
failureHandler.onBeginFailure(e.getTransaction(), e.getCause());
throw e.getCause();
case CommitFailure:
succeed = false;
failureHandler.onCommitFailure(e.getTransaction(), e.getCause());
throw e.getCause();
case RollbackFailure:
failureHandler.onRollbackFailure(e.getTransaction(), e.getOriginalException());
throw e.getOriginalException();
case RollbackRetrying:
failureHandler.onRollbackRetrying(e.getTransaction(), e.getOriginalException());
throw e.getOriginalException();
default:
throw new ShouldNeverHappenException(String.format("Unknown TransactionalExecutor.Code: %s", code));
}
} finally {
if (degradeCheck) {
EVENT_BUS.post(new DegradeCheckEvent(succeed));
}
}
}
发生异常catch后,会获取 TransactionalExecutor.Code code = e.getCode(),根据这个code,调用failureHandler相应的方法(可自定义实现)
最后在finally中发送消息到事务总线。
TransactionalTemplate的execute方法
>>>>>>>>> 未完待续 >>>>>>>>>
4、 seata怎么处理回滚和提交等操作
使用定时线程池类 io.seata.server.coordinator.DefaultCoordinator
private ScheduledThreadPoolExecutor retryRollbacking = new ScheduledThreadPoolExecutor(1,
new NamedThreadFactory("RetryRollbacking", 1));
private ScheduledThreadPoolExecutor retryCommitting = new ScheduledThreadPoolExecutor(1,
new NamedThreadFactory("RetryCommitting", 1));
private ScheduledThreadPoolExecutor asyncCommitting = new ScheduledThreadPoolExecutor(1,
new NamedThreadFactory("AsyncCommitting", 1));
private ScheduledThreadPoolExecutor timeoutCheck = new ScheduledThreadPoolExecutor(1,
new NamedThreadFactory("TxTimeoutCheck", 1));
private ScheduledThreadPoolExecutor undoLogDelete = new ScheduledThreadPoolExecutor(1,
new NamedThreadFactory("UndoLogDelete", 1));
5、怎么控制事务失败回滚重试
## server configuration, only used in server side
server {
recovery {
#schedule committing retry period in milliseconds
committingRetryPeriod = 1000
#schedule asyn committing retry period in milliseconds
asynCommittingRetryPeriod = 1000
#schedule rollbacking retry period in milliseconds
rollbackingRetryPeriod = 1000
#schedule timeout retry period in milliseconds
timeoutRetryPeriod = 1000
}
undo {
logSaveDays = 7
#schedule delete expired undo_log in milliseconds
logDeletePeriod = 86400000
}
#check auth
enableCheckAuth = true
#unit ms,s,m,h,d represents milliseconds, seconds, minutes, hours, days, default permanent
maxCommitRetryTimeout = "-1"
maxRollbackRetryTimeout = "30000"
rollbackRetryTimeoutUnlockEnable = false
retryDeadThreshold = 130000
}
server.recovery 中4个重试期间值,在 io.seata.server.coordinator.DefaultCoordinator#init 方法里初始化
maxRollbackRetryTimeout 默认值是-1,表示会回滚失败会一直重试。
示例调整为30000毫秒,从全局事务开始计算时间,在源码中 io.seata.server.coordinator.DefaultCoordinator#handleRetryRollbacking 方法里用到