4、Spring事務回滾

接第2節事務流程,這是第5點解析數據庫

回滾邏輯以下:安全

  1. 判斷是否存在事務,只有存在事務才執行回滾
  2. 根據異常類型判斷是否回滾。若是異常類型不符合,仍然會提交事務
  3. 回滾處理

詳細解析app

  1. 判斷是否存在事務,只有存在事務才執行回滾,便是否有@Transactional事務註解或相關事務切面
  2. 根據異常類型判斷是否回滾。若是異常類型不符合,仍然會提交事務

根據@Transactional註解中rollbackFor、rollbackForClassName、noRollbackForClassName配置的值,找到最符合ex的異常類型,若是符合的異常類型不是NoRollbackRuleAttribute,則能夠執行回滾。
若是@Transactional沒有配置,則默認使用RuntimeException和Error異常。
代碼以下:ide

@Override
public boolean rollbackOn(Throwable ex) {
    if (logger.isTraceEnabled()) {
        logger.trace("Applying rules to determine whether transaction should rollback on " + ex);
    }

    RollbackRuleAttribute winner = null;
    int deepest = Integer.MAX_VALUE;

    //rollbackRules保存@Transactional註解中rollbackFor、rollbackForClassName、noRollbackForClassName配置的值
    if (this.rollbackRules != null) {
        for (RollbackRuleAttribute rule : this.rollbackRules) {
            int depth = rule.getDepth(ex);
            if (depth >= 0 && depth < deepest) {
                deepest = depth;
                winner = rule;
            }
        }
    }

    if (logger.isTraceEnabled()) {
        logger.trace("Winning rollback rule is: " + winner);
    }

    // User superclass behavior (rollback on unchecked) if no rule matches.
    //若@Transactional沒有配置,默認調用父類的
    if (winner == null) {
        logger.trace("No relevant rollback rule found: applying default rules");
        return super.rollbackOn(ex);
    }

    return !(winner instanceof NoRollbackRuleAttribute);
}

//super
@Override
public boolean rollbackOn(Throwable ex) {
    return (ex instanceof RuntimeException || ex instanceof Error);
}
  1. 回滾處理
  • 若是存在安全點,則回滾事務至安全點,這個主要是處理嵌套事務,回滾安全點的操做仍是交給了數據庫處理.
  • 當前事務是一個新事務時,那麼直接回滾,使用的是DataSourceTransactionManager事務管理器,因此調用DataSourceTransactionManager#doRollback,直接調用數據庫鏈接的回滾方法。
  • 當前存在事務,但又不是一個新的事務,只把事務的狀態標記爲read-only,等到事務鏈執行完畢後,統一回滾,調用DataSourceTransactionManager#doSetRollbackOnly
  • 清空記錄的資源並將掛起的資源恢復

代碼以下:this

private void processRollback(DefaultTransactionStatus status) {
    try {
        try {
            triggerBeforeCompletion(status);
            //若是有安全點,回滾至安全點
            if (status.hasSavepoint()) {
                if (status.isDebug()) {
                    logger.debug("Rolling back transaction to savepoint");
                }
                status.rollbackToHeldSavepoint();
            }
            //若是是新事務,回滾事務
            else if (status.isNewTransaction()) {
                if (status.isDebug()) {
                    logger.debug("Initiating transaction rollback");
                }
                doRollback(status);
            }
            //若是有事務但不是新事務,則把標記事務狀態,等事務鏈執行完畢後統一回滾
            else if (status.hasTransaction()) {
                if (status.isLocalRollbackOnly() || isGlobalRollbackOnParticipationFailure()) {
                    if (status.isDebug()) {
                        logger.debug("Participating transaction failed - marking existing transaction as rollback-only");
                    }
                    doSetRollbackOnly(status);
                }
                else {
                    if (status.isDebug()) {
                        logger.debug("Participating transaction failed - letting transaction originator decide on rollback");
                    }
                }
            }
            else {
                logger.debug("Should roll back transaction but cannot - no transaction available");
            }
        }
        catch (RuntimeException ex) {
            triggerAfterCompletion(status, TransactionSynchronization.STATUS_UNKNOWN);
            throw ex;
        }
        catch (Error err) {
            triggerAfterCompletion(status, TransactionSynchronization.STATUS_UNKNOWN);
            throw err;
        }
        triggerAfterCompletion(status, TransactionSynchronization.STATUS_ROLLED_BACK);
    }
    finally {
        //清空記錄的資源並將掛起的資源恢復
        cleanupAfterCompletion(status);
    }
}
相關文章
相關標籤/搜索