分布式事务Seata

官方文档: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 方法里用到

 

 

 

 

 

 

 

 

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章