45--Spring @Transactional聲明式事物(二)事物創(chuàng)建簡析

1.引

上一節(jié)分析了Spring實現(xiàn)事物管理的步驟纸型,本篇分析Spring事物的創(chuàng)建過程叫编。

2.事物創(chuàng)建方法簡析
protected TransactionInfo createTransactionIfNecessary(@Nullable PlatformTransactionManager tm,
                                                           @Nullable TransactionAttribute txAttr,
                                                           final String joinpointIdentification) {

    // If no name specified, apply method identification as transaction name.
    // 1. 如果沒有指定名稱援雇,則應(yīng)用方法標識作為事務(wù)名稱枷莉。
    if (txAttr != null && txAttr.getName() == null) {
        txAttr = new DelegatingTransactionAttribute(txAttr) {
            @Override
            public String getName() {
                return joinpointIdentification;
            }
        };
    }

    // 2.獲取TransactionStatus對象
    TransactionStatus status = null;
    if (txAttr != null) {
        if (tm != null) {
            // 重點: 根據(jù)指定的傳播行為臣嚣,返回當前活動的事務(wù)或創(chuàng)建新事務(wù)净刮。
            status = tm.getTransaction(txAttr);
        } else {
            if (logger.isDebugEnabled()) {
                logger.debug("Skipping transactional joinpoint [" + joinpointIdentification +
                        "] because no transaction manager has been configured");
            }
        }
    }
    // 3.創(chuàng)建TransactionInfo對象
    return prepareTransactionInfo(tm, txAttr, joinpointIdentification, status);
}

最重要的是TransactionStatus對象的獲取過程,以及創(chuàng)建TransactionInfo對象硅则,下面分別單獨介紹淹父。

3.獲取TransactionStatus對象,即Spring事物創(chuàng)建過程簡析
public final TransactionStatus getTransaction(@Nullable TransactionDefinition definition) throws TransactionException {

    // 1.獲取當前事物對象(如果當前已經(jīng)存在了事物)
    Object transaction = doGetTransaction();

    // Cache debug flag to avoid repeated checks.
    boolean debugEnabled = logger.isDebugEnabled();

    // 如果TransactionDefinition為空,默認創(chuàng)建DefaultTransactionDefinition對象
    if (definition == null) {
        // Use defaults if no transaction definition given.
        definition = new DefaultTransactionDefinition();
    }

    // 2.如果當前已經(jīng)存在事物
    // 重點:
    // 如果當前已經(jīng)存在啟動的事物,則根據(jù)本次要新建的事物傳播特性進行評估,以決定對新事物的后續(xù)處理
    if (isExistingTransaction(transaction)) {
        // Existing transaction found -> check propagation behavior to find out how to behave.
        return handleExistingTransaction(definition, transaction, debugEnabled);
    }

    // 3.如果當前不存在事物

    // Check definition settings for new transaction.
    // 3.1 如果事物定義的超時時間,小于默認的超時時間,拋出異常,TransactionDefinition.TIMEOUT_DEFAULT --> -1
    if (definition.getTimeout() < TransactionDefinition.TIMEOUT_DEFAULT) {
        throw new InvalidTimeoutException("Invalid transaction timeout", definition.getTimeout());
    }

    // No existing transaction found -> check propagation behavior to find out how to proceed.
    // 3.2 如果當前事物特性為PROPAGATION_MANDATORY,則拋出異常(因為當前事物還沒創(chuàng)建結(jié)束并開啟...)
    // PROPAGATION_MANDATORY --> 使用當前事物怎虫,如果當前沒有事物暑认,則拋出異常。
    if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_MANDATORY) {
        throw new IllegalTransactionStateException("No existing transaction found for transaction marked with propagation 'mandatory'");
    }

    // 3.3 如果事物傳播特性為以下三種,則創(chuàng)建新的事物:
    // PROPAGATION_REQUIRED --> 如果當前沒有事物大审,則新建一個事物蘸际;如果已經(jīng)存在一個事物,則加入到這個事物中徒扶。
    // PROPAGATION_REQUIRES_NEW --> 新建事物粮彤,如果當前已經(jīng)存在事物,則掛起當前事物姜骡。
    // PROPAGATION_NESTED --> 如果當前存在事物导坟,則在嵌套事物內(nèi)執(zhí)行;如果當前沒有事物圈澈,則與PROPAGATION_REQUIRED傳播特性相同
    else if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRED
            || definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW
            || definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {
        SuspendedResourcesHolder suspendedResources = suspend(null);
        if (debugEnabled) {
            // 從日志打印,也可以看見當前要創(chuàng)建一個名為definition.getName()的新事物了...
            logger.debug("Creating new transaction with name [" + definition.getName() + "]: " + definition);
        }
        try {
            boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
            // 創(chuàng)建DefaultTransactionStatus對象實例
            DefaultTransactionStatus status = newTransactionStatus(
                    definition,
                    transaction,
                    true,
                    newSynchronization,
                    debugEnabled,
                    suspendedResources);
            // 開啟事物
            doBegin(transaction, definition);
            // 初始化事務(wù)同步惫周。
            prepareSynchronization(status, definition);
            return status;
        }
        catch (RuntimeException | Error ex) {
            resume(null, suspendedResources);
            throw ex;
        }
    }
    // 3.4 對于其他的三種傳播特性,無需開啟新的事物
    // PROPAGATION_SUPPORTS --> 支持當前事物,如果當前沒有事物康栈,則以非事物方式執(zhí)行
    // PROPAGATION_NOT_SUPPORTED --> 以非事物方式執(zhí)行闯两,如果當前存在事物,則掛起當前事物
    // PROPAGATION_NEVER --> 以非事物方式執(zhí)行谅将,如果當前存在事物,則拋出異常
    else {
        // Create "empty" transaction: no actual transaction, but potentially synchronization.
        if (definition.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT && logger.isWarnEnabled()) {
            logger.warn("Custom isolation level specified but no actual transaction initiated; "
                    + "isolation level will effectively be ignored: " + definition);
        }
        boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);
        return prepareTransactionStatus(
                definition,
                null,
                true,
                newSynchronization,
                debugEnabled,
                null);
    }
}

該方法可以說是Spring事物最最關(guān)鍵重慢、最最核心的方法了饥臂。對于這里比較重要的的方法,逐個分析似踱。隅熙。。

3.1獲取當前事物對象(如果當前已經(jīng)存在了事物)

對于不同的事物管理器核芽,獲取的方法也是不同的囚戚,本例使用的是DataSourceTransactionManager

protected Object doGetTransaction() {
    DataSourceTransactionObject txObject = new DataSourceTransactionObject();
    // 是否允許使用保存點
    txObject.setSavepointAllowed(isNestedTransactionAllowed());
    // 從當前線程中獲取ConnectionHolder對象
    ConnectionHolder conHolder = (ConnectionHolder) TransactionSynchronizationManager.getResource(obtainDataSource());
    txObject.setConnectionHolder(conHolder, false);
    return txObject;
}
3.2 如果當前已經(jīng)存在事物

這里,涉及到事物嵌套轧简,留在后面單獨分析驰坊。。哮独。

3.3 如果當前不存在事物

這里就不會涉及到事物的嵌套處理了拳芙,分析起來也比較簡單點察藐,接下來的處理就是要根據(jù)我們配置的事物傳播特性,去逐個分析了

3.3.1 超時時間處理

很簡單舟扎,如果自定義的超時時間小于默認的超時時間分飞,則拋出異常

3.3.2 處理PROPAGATION_MANDATORY傳播特性

如果我們定義的事物傳播特性為PROPAGATION_MANDATORY,那么這里會拋出異常睹限,因為當前沒有事物譬猫,或者說事物還在創(chuàng)建中。而PROPAGATION_MANDATORY特性是:使用當前事物羡疗,如果當前沒有事物染服,則拋出異常。

3.3.3 處理PROPAGATION_REQUIRED顺囊、PROPAGATION_REQUIRES_NEW肌索、PROPAGATION_NESTED傳播特性

先來回顧一下這三種傳播特性:
PROPAGATION_REQUIRED --> 如果當前沒有事物,則新建一個事物特碳;如果已經(jīng)存在一個事物诚亚,則加入到這個事物中。
PROPAGATION_REQUIRES_NEW --> 新建事物午乓,如果當前已經(jīng)存在事物站宗,則掛起當前事物。
PROPAGATION_NESTED --> 如果當前存在事物益愈,則在嵌套事物內(nèi)執(zhí)行梢灭;如果當前沒有事物,則與PROPAGATION_REQUIRED傳播特性相同

因為當前不存在事物蒸其,根據(jù)這幾種特性敏释,在這里就要新建事物了,代碼片段:

try {
    boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
    // 創(chuàng)建DefaultTransactionStatus對象實例
    DefaultTransactionStatus status = newTransactionStatus(
            definition,
            transaction,
            true,
            newSynchronization,
            debugEnabled,
            suspendedResources);
    // 開啟事物
    doBegin(transaction, definition);
    // 初始化事務(wù)同步摸袁。
    prepareSynchronization(status, definition);
    return status;
}

小分支太多了钥顽,下面單獨在開一篇介紹吧。靠汁。蜂大。

3.3.4 處理PROPAGATION_SUPPORTS捐下、PROPAGATION_NOT_SUPPORTED锁保、PROPAGATION_NEVER傳播特性

回顧一下這三種特性:
PROPAGATION_SUPPORTS --> 支持當前事物寂汇,如果當前沒有事物蚊丐,則以非事物方式執(zhí)行
PROPAGATION_NOT_SUPPORTED --> 以非事物方式執(zhí)行桌粉,如果當前存在事物绷雏,則掛起當前事物
PROPAGATION_NEVER --> 以非事物方式執(zhí)行紊遵,如果當前存在事物窄绒,則拋出異常

因為當前不存在事物,根據(jù)這幾種特性耳高,無需開啟真正的事物扎瓶。

4.創(chuàng)建TransactionInfo對象

這里我們假設(shè)事物已經(jīng)創(chuàng)建完成了(上一步?jīng)]有分析事物具體的創(chuàng)建過程,留在下一篇介紹)泌枪,接下來就要創(chuàng)建TransactionInfo對象了概荷,該對象持有了上一步創(chuàng)建的事物信息。

protected TransactionInfo prepareTransactionInfo(@Nullable PlatformTransactionManager tm,
                                                     @Nullable TransactionAttribute txAttr,
                                                     String joinpointIdentification,
                                                     @Nullable TransactionStatus status) {
    // 創(chuàng)建TransactionInfo對象
    TransactionInfo txInfo = new TransactionInfo(tm, txAttr, joinpointIdentification);
    // 如果事物標簽不為空,則將TransactionStatus對象賦予TransactionInfo
    if (txAttr != null) {
        // We need a transaction for this method...
        if (logger.isTraceEnabled()) {
            logger.trace("Getting transaction for [" + txInfo.getJoinpointIdentification() + "]");
        }
        // The transaction manager will flag an error if an incompatible tx already exists.
        txInfo.newTransactionStatus(status);
    } else {
        // The TransactionInfo.hasTransaction() method will return false. We created it only
        // to preserve the integrity of the ThreadLocal stack maintained in this class.
        if (logger.isTraceEnabled()) {
            logger.trace("Don't need to create transaction for [" + joinpointIdentification + "]: This method isn't transactional.");
        }
    }

    // We always bind the TransactionInfo to the thread, even if we didn't create
    // a new transaction here. This guarantees that the TransactionInfo stack
    // will be managed correctly even if no transaction was created by this aspect.
    // 這里:不論是否開啟了新的事物,都將TransactionInfo綁定到當前線程,以保證TransactionInfo堆棧的完整性碌燕。
    txInfo.bindToThread();
    return txInfo;
}

基本上就是簡單的賦值操作误证,并在最后將創(chuàng)建的TransactionInfo綁定到當前線程。注意修壕,在綁定過程中愈捅,當前事物信息是會獲取已有的事物信息并一起綁定到transactionInfoHolder變量的。這樣就可能會形成一個事物鏈慈鸠。

private void bindToThread() {
    // Expose current TransactionStatus, preserving any existing TransactionStatus
    // for restoration after this transaction is complete.
    this.oldTransactionInfo = transactionInfoHolder.get();
    transactionInfoHolder.set(this);
}

其中transactionInfoHolder是個ThreadLocal類型的變量:

private static final ThreadLocal<TransactionInfo> transactionInfoHolder = new NamedThreadLocal<>("Current aspect-driven transaction");

本篇的分析就到此了蓝谨,因為這里的分支實在是太多,還是多開幾篇吧青团!

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末譬巫,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子督笆,更是在濱河造成了極大的恐慌芦昔,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,270評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件娃肿,死亡現(xiàn)場離奇詭異咕缎,居然都是意外死亡,警方通過查閱死者的電腦和手機料扰,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,489評論 3 395
  • 文/潘曉璐 我一進店門凭豪,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人晒杈,你說我怎么就攤上這事墅诡。” “怎么了桐智?”我有些...
    開封第一講書人閱讀 165,630評論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長烟馅。 經(jīng)常有香客問我说庭,道長,這世上最難降的妖魔是什么郑趁? 我笑而不...
    開封第一講書人閱讀 58,906評論 1 295
  • 正文 為了忘掉前任刊驴,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘捆憎。我一直安慰自己舅柜,他們只是感情好,可當我...
    茶點故事閱讀 67,928評論 6 392
  • 文/花漫 我一把揭開白布躲惰。 她就那樣靜靜地躺著致份,像睡著了一般。 火紅的嫁衣襯著肌膚如雪础拨。 梳的紋絲不亂的頭發(fā)上氮块,一...
    開封第一講書人閱讀 51,718評論 1 305
  • 那天,我揣著相機與錄音诡宗,去河邊找鬼滔蝉。 笑死,一個胖子當著我的面吹牛塔沃,可吹牛的內(nèi)容都是我干的蝠引。 我是一名探鬼主播,決...
    沈念sama閱讀 40,442評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼蛀柴,長吁一口氣:“原來是場噩夢啊……” “哼螃概!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起名扛,我...
    開封第一講書人閱讀 39,345評論 0 276
  • 序言:老撾萬榮一對情侶失蹤谅年,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后肮韧,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體融蹂,經(jīng)...
    沈念sama閱讀 45,802評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,984評論 3 337
  • 正文 我和宋清朗相戀三年弄企,在試婚紗的時候發(fā)現(xiàn)自己被綠了超燃。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,117評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡拘领,死狀恐怖意乓,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情约素,我是刑警寧澤届良,帶...
    沈念sama閱讀 35,810評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站圣猎,受9級特大地震影響士葫,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜送悔,卻給世界環(huán)境...
    茶點故事閱讀 41,462評論 3 331
  • 文/蒙蒙 一慢显、第九天 我趴在偏房一處隱蔽的房頂上張望爪模。 院中可真熱鬧,春花似錦荚藻、人聲如沸屋灌。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,011評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽共郭。三九已至,卻和暖如春侦香,著一層夾襖步出監(jiān)牢的瞬間落塑,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,139評論 1 272
  • 我被黑心中介騙來泰國打工罐韩, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留憾赁,地道東北人。 一個月前我還...
    沈念sama閱讀 48,377評論 3 373
  • 正文 我出身青樓散吵,卻偏偏與公主長得像龙考,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子矾睦,可洞房花燭夜當晚...
    茶點故事閱讀 45,060評論 2 355

推薦閱讀更多精彩內(nèi)容