官方文檔: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 方法裏用到