46--Spring @Transactional聲明式事物(三)事物創(chuàng)建

1.引

上一節(jié)已經(jīng)分析了了在單service單方法下的事物創(chuàng)建過程以及其后續(xù)處理工作娶桦,當然還缺少真正創(chuàng)建事物的分析,本篇接續(xù)蓬蝶。先來回顧一下事物創(chuàng)建的代碼片段:

try {
    boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
    // 創(chuàng)建DefaultTransactionStatus對象實例
    DefaultTransactionStatus status = newTransactionStatus(
            definition,
            transaction,
            true,
            newSynchronization,
            debugEnabled,
            suspendedResources);
    // 開啟事物
    doBegin(transaction, definition);
    // 初始化事務同步耳贬。
    prepareSynchronization(status, definition);
    return status;
}
2.創(chuàng)建DefaultTransactionStatus對象
/**
 * 創(chuàng)建DefaultTransactionStatus實例
 * Create a TransactionStatus instance for the given arguments.
 */
protected DefaultTransactionStatus newTransactionStatus(
        TransactionDefinition definition,
        @Nullable Object transaction,
        boolean newTransaction,
        boolean newSynchronization,
        boolean debug,
        @Nullable Object suspendedResources) {

    boolean actualNewSynchronization = newSynchronization && !TransactionSynchronizationManager.isSynchronizationActive();

    return new DefaultTransactionStatus(
            transaction,
            newTransaction,
            actualNewSynchronization,
            definition.isReadOnly(),
            debug,
            suspendedResources);
}

//構造方法
public DefaultTransactionStatus(
            @Nullable Object transaction,
            boolean newTransaction,
            boolean newSynchronization,
            boolean readOnly,
            boolean debug,
            @Nullable Object suspendedResources) {

    this.transaction = transaction;
    this.newTransaction = newTransaction;
    this.newSynchronization = newSynchronization;
    this.readOnly = readOnly;
    this.debug = debug;
    this.suspendedResources = suspendedResources;
}
3.開啟事物

針對不同的事物管理器會有不同的事物開啟過程,本例我們只看DataSourceTransactionManager下的事物開啟過程:

protected void doBegin(Object transaction, TransactionDefinition definition) {
    DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
    Connection con = null;

    try {
        // ConnectionHolder簡介:包裝JDBC連接的資源容器碌燕。DataSourceTransactionManager將該類的實例綁定到特定數(shù)據(jù)源的線程误证。
        // 如果txObject沒有ConnectionHolder或者connectionHolder并沒有加同步鎖,則為其設置ConnectionHolder并加同步鎖
        if (!txObject.hasConnectionHolder() || txObject.getConnectionHolder().isSynchronizedWithTransaction()) {
            // 從數(shù)據(jù)源獲取連接
            Connection newCon = obtainDataSource().getConnection();
            if (logger.isDebugEnabled()) {
                logger.debug("Acquired Connection [" + newCon + "] for JDBC transaction");
            }
            // 設置DataSourceTransactionObject的ConnectionHolder對象
            txObject.setConnectionHolder(new ConnectionHolder(newCon), true);
        }

        // 設置同步鎖標記
        txObject.getConnectionHolder().setSynchronizedWithTransaction(true);

        // 從ConnectionHolder對象中獲取連接
        con = txObject.getConnectionHolder().getConnection();

        // 設置連接的只讀屬性和數(shù)據(jù)庫事物隔離級別
        Integer previousIsolationLevel = DataSourceUtils.prepareConnectionForTransaction(con, definition);
        txObject.setPreviousIsolationLevel(previousIsolationLevel);

        // Switch to manual commit if necessary. This is very expensive in some JDBC drivers,
        // so we don't want to do it unnecessarily
        // (for example if we've explicitly configured the connection pool to set it already).
        // 如果需要,切換到手動提交修壕。
        // 在某些JDBC驅動程序中愈捅,這是非常昂貴的,所以我們不想做不必要的事情
        // (例如慈鸠,如果我們已經(jīng)顯式地配置了連接池來設置它)蓝谨。
        // 所以:如果連接設置了自動提交,這里要將其轉換為手動提交
        if (con.getAutoCommit()) {
            txObject.setMustRestoreAutoCommit(true);
            if (logger.isDebugEnabled()) {
                logger.debug("Switching JDBC Connection [" + con + "] to manual commit");
            }
            con.setAutoCommit(false);
        }

        // 設置當前事物只讀,如果定義了只讀屬性為true
        prepareTransactionalConnection(con, definition);
        // 設置當前事物為已激活
        txObject.getConnectionHolder().setTransactionActive(true);

        // 設置超時時間(如果超時時間不等于默認超時時間)
        int timeout = determineTimeout(definition);
        if (timeout != TransactionDefinition.TIMEOUT_DEFAULT) {
            txObject.getConnectionHolder().setTimeoutInSeconds(timeout);
        }

        // Bind the connection holder to the thread.
        // 綁定ConnectionHolder到當前線程
        if (txObject.isNewConnectionHolder()) {
            // 即TransactionSynchronizationManager類的resources對象:
            // 該對象保存每個事物線程對應的connection或session等類型的資源
            // private static final ThreadLocal<Map<Object, Object>> resources = new NamedThreadLocal<>("Transactional resources");
            TransactionSynchronizationManager.bindResource(obtainDataSource(), txObject.getConnectionHolder());
        }
    }

    // 異常處理
    catch (Throwable ex) {
        if (txObject.isNewConnectionHolder()) {
            DataSourceUtils.releaseConnection(con, obtainDataSource());
            txObject.setConnectionHolder(null, false);
        }
        throw new CannotCreateTransactionException("Could not open JDBC Connection for transaction", ex);
    }
}

該方法也比較簡單,相信大家都能看懂青团,其中關于ConnectionHolder(前文沒有講解)對象譬巫,也已經(jīng)在注釋里做過介紹了。

4.初始化事物同步
/**
 * 根據(jù)需要初始化事務同步督笆。
 * Initialize transaction synchronization as appropriate.
 */
protected void prepareSynchronization(DefaultTransactionStatus status, TransactionDefinition definition) {
    if (status.isNewSynchronization()) {
        // 設置事物激活狀態(tài)
        TransactionSynchronizationManager.setActualTransactionActive(status.hasTransaction());
        // 設置事物隔離級別
        TransactionSynchronizationManager.setCurrentTransactionIsolationLevel(
                definition.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT ? definition.getIsolationLevel() : null);
        // 設置事物只讀屬性
        TransactionSynchronizationManager.setCurrentTransactionReadOnly(definition.isReadOnly());
        // 設置事物名稱
        TransactionSynchronizationManager.setCurrentTransactionName(definition.getName());
        // 激活當前線程的事務同步芦昔。事務管理器在事務開始時調用。
        TransactionSynchronizationManager.initSynchronization();
    }
}

總體來講上面的內容還是比較簡單的娃肿,不做過多的分析了烟零。

5.其他事物特性處理

以上分析的都是基于單service下單個方法調用的事物創(chuàng)建過程,且當前不存在事物咸作,那么對于其它的事物的特性呢?接下來就分析一下其他的特性宵睦,其實前面的章節(jié)已經(jīng)有過簡單的介紹了记罚,這里再詳細分析下。對于PROPAGATION_NESTED特性會直接拋出異常壳嚎。

那么下面介紹一下PROPAGATION_SUPPORTS桐智、PROPAGATION_NOT_SUPPORTED、PROPAGATION_NEVER特性事物處理過程烟馅,先來看一下代碼片段:

// 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);
protected final DefaultTransactionStatus prepareTransactionStatus(
        TransactionDefinition definition,
        @Nullable Object transaction,
        boolean newTransaction,
        boolean newSynchronization,
        boolean debug,
        @Nullable Object suspendedResources) {

    DefaultTransactionStatus status = newTransactionStatus(
            definition,
            transaction,
            newTransaction,
            newSynchronization,
            debug,
            suspendedResources);

    prepareSynchronization(status, definition);
    return status;
}

從代碼里可以看到说庭,該處理與創(chuàng)建真正的事物的過程相似,只是傳遞的參數(shù)不同罷了郑趁。大家可以多設定幾種傳播特性刊驴,跟蹤一下代碼即可。

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末寡润,一起剝皮案震驚了整個濱河市捆憎,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌梭纹,老刑警劉巖躲惰,帶你破解...
    沈念sama閱讀 206,723評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異变抽,居然都是意外死亡础拨,警方通過查閱死者的電腦和手機氮块,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,485評論 2 382
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來诡宗,“玉大人滔蝉,你說我怎么就攤上這事×沤梗” “怎么了锰提?”我有些...
    開封第一講書人閱讀 152,998評論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長芳悲。 經(jīng)常有香客問我立肘,道長,這世上最難降的妖魔是什么名扛? 我笑而不...
    開封第一講書人閱讀 55,323評論 1 279
  • 正文 為了忘掉前任谅年,我火速辦了婚禮,結果婚禮上肮韧,老公的妹妹穿的比我還像新娘融蹂。我一直安慰自己,他們只是感情好弄企,可當我...
    茶點故事閱讀 64,355評論 5 374
  • 文/花漫 我一把揭開白布超燃。 她就那樣靜靜地躺著,像睡著了一般拘领。 火紅的嫁衣襯著肌膚如雪意乓。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,079評論 1 285
  • 那天约素,我揣著相機與錄音届良,去河邊找鬼。 笑死圣猎,一個胖子當著我的面吹牛士葫,可吹牛的內容都是我干的。 我是一名探鬼主播送悔,決...
    沈念sama閱讀 38,389評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼慢显,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了欠啤?” 一聲冷哼從身側響起鳍怨,我...
    開封第一講書人閱讀 37,019評論 0 259
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎跪妥,沒想到半個月后鞋喇,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,519評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡眉撵,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 35,971評論 2 325
  • 正文 我和宋清朗相戀三年侦香,在試婚紗的時候發(fā)現(xiàn)自己被綠了落塑。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,100評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡罐韩,死狀恐怖憾赁,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情散吵,我是刑警寧澤龙考,帶...
    沈念sama閱讀 33,738評論 4 324
  • 正文 年R本政府宣布,位于F島的核電站矾睦,受9級特大地震影響晦款,放射性物質發(fā)生泄漏。R本人自食惡果不足惜枚冗,卻給世界環(huán)境...
    茶點故事閱讀 39,293評論 3 307
  • 文/蒙蒙 一缓溅、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧赁温,春花似錦坛怪、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,289評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至稚疹,卻和暖如春沉帮,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背贫堰。 一陣腳步聲響...
    開封第一講書人閱讀 31,517評論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留待牵,地道東北人其屏。 一個月前我還...
    沈念sama閱讀 45,547評論 2 354
  • 正文 我出身青樓,卻偏偏與公主長得像缨该,于是被迫代替她去往敵國和親偎行。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 42,834評論 2 345

推薦閱讀更多精彩內容

  • 1.引 上一節(jié)分析了Spring實現(xiàn)事物管理的步驟贰拿,本篇分析Spring事物的創(chuàng)建過程蛤袒。 2.事物創(chuàng)建方法簡析 最...
    閑來也無事閱讀 818評論 0 5
  • 很多人喜歡這篇文章,特此同步過來 由淺入深談論spring事務 前言 這篇其實也要歸納到《常識》系列中膨更,但這重點又...
    碼農戲碼閱讀 4,706評論 2 59
  • springAop:面向切面的編程 應用場景:權限控制妙真、事物管理、日志打印等等荚守,就是在不同的方法中重復用到相同的代...
    HJJ_3c00閱讀 328評論 0 0
  • 有時候太久沒寫東西,腦袋里總是亂做一團锈候,又或者空無一物薄料。 也許是經(jīng)歷的事情太多了,也許是這充滿磨練的一年有你的陪伴...
    深夜卡片閱讀 870評論 0 0
  • 每個人都有自己的選擇泵琳,不要隨波逐流摄职,關注你的內心,用心生活获列,生活應該過的灑脫谷市,不要在意別人的眼光,做自己就是最好的...
    sunshine1980閱讀 78評論 0 0