Transaction 事務(wù)

一箕慧、官網(wǎng)地址:
https://docs.spring.io/spring/docs/5.1.3.RELEASE/spring-framework-reference/data-access.html#
Transaction
二雳攘、實現(xiàn)方式:
2.1 通過xml配置:
2.1.1配置transanctionManager, 屬性 dataSource

<bean id="txManager" 
      class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> 
      <property name="dataSource" ref="dataSource"/> 
</bean>

2.1.2 基于Aop 配置事務(wù)增強 <tx> 標簽 是transaction 提供的標簽,在這里可以配置指定某些方法定義事務(wù)的傳播行為汁尺,隔離級別。


image.png

2.2 通過注解配置:
開啟spring 注解事務(wù)的注解:@EnableTransactionManagement
在要加事務(wù)管理的類或方法上加@Transactional多律,如果需要對事務(wù)的其他屬性進行配置時痴突,即在注解上面配置相關(guān)屬性即可。


image.png

2.3 編程式事務(wù):
1 定義TransactionDefinition 作為transactionManager的入?yún)l件來獲取TransactionStatus狼荞,其中DefaultTransactionDefinition 定義了事務(wù)的屬性辽装。

        TransactionDefinition definition = new DefaultTransactionDefinition(); 
        TransactionStatus status = txManager.getTransaction(definition);
      try{
            //業(yè)務(wù)
          txManager.commit(status);
        }catch(Exception e){
            //出現(xiàn)異常手動回滾
            txManager.rollback(status );
        }
還有一種直接獲取TransactionStatus 并將他設(shè)置成rollbackOnly
public void resolvePosition() {
    try {
        // some business logic...
    } catch (NoProductInStockException ex) {
        // trigger rollback programmatically
        TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
    }
}

2 spring 還提供了事務(wù)模版用來管理事務(wù):
TransactionTemplate 執(zhí)行 execute();方法來完成相關(guān)事務(wù)操作。
可以自己在此基礎(chǔ)上造個輪子:

package com.chen.springboot.bootlearn.template;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.TransactionCallbackWithoutResult;
import org.springframework.transaction.support.TransactionTemplate;

@Component
public class SpringTransaction {

    @Autowired
    private TransactionTemplate transactionTemplate;  // TransactionTemplate 作為spring bean維護
    
    //提供一個模版方法 子類重寫具體業(yè)務(wù)
    public Object execute(TransactionTemplates templates) {
        Object result = new Object();
        transactionTemplate.execute(new TransactionCallbackWithoutResult() {
            @Override
            protected void doInTransactionWithoutResult(TransactionStatus transactionStatus) {
                try {
                    templates.lock();
                } finally {
                    System.out.println("Lock");
                }
                try {
                    templates.check();
                } finally {
                    System.out.println("Check");
                }
                try {
                    templates.process();
                } finally {
                    System.out.println("Process");
                }
            }
        });
        return result;
    }
}

遇到需要調(diào)用事務(wù)的時候 直接執(zhí)行 execute()方法即可

    @Override
    public Object addCount(User user) {
        Object object = new Object();
        transaction.execute(new TransactionTemplates() {
            @Override
            public void check() {
            }
            @Override
            public void lock() {
            }
            @Override
            public void process() {
            }
        });
        return object;
    }

三 事務(wù)API
Spring事務(wù)核心的API:
3.1 : PlatformTransactionManager,平臺級的事務(wù)管理器相味,它抽象定義了事務(wù)管理行為拾积,不同
的事務(wù)管理實現(xiàn)實現(xiàn)該接口。我們編程面向該接口丰涉。繼承關(guān)系圖如下所示:


image.png

3.1.1 抽象方法也很簡單:


image.png

3.2 : TransactionDefinition:事務(wù)定義拓巧。Spring 事務(wù)管理框架將為我們管理事務(wù),但不清楚該
如何替我們管理一死,我們就通過事務(wù)定義來定義我們需要的事務(wù)管理信息肛度,把這些信息給事務(wù)
管理器,它就知道我們的意圖了投慈。
接口 的結(jié)構(gòu)圖如下所示:


image.png

繼承關(guān)系圖:


image.png

3.3:TransactionStatus 事務(wù)狀態(tài)承耿,持有事務(wù)的狀態(tài)信息。事務(wù)管理代碼可通過它獲取事務(wù)狀態(tài)伪煤、
以及顯式地設(shè)置回滾(代替異常的方式)加袋。它繼承了 SavePoint 接口。在它的實現(xiàn)中會持有事
務(wù)的很多對象:如事務(wù)對象带族、被掛起的事務(wù)資源等锁荔。
從 TransactionManager 中獲取事務(wù)得到它,提交/回滾事務(wù)時要給入它:
類結(jié)構(gòu)圖:


image.png

繼承關(guān)系圖:


image.png

四 具體實現(xiàn)流程:
驗證:DataSourceTransactionManager
DataSourceTransactionManager 是基于 jdbc connection 的本地事務(wù)管理實現(xiàn)。多個方法
調(diào)用參與到同一個事務(wù)阳堕,是通過共用 connection 來完成的跋理。
通過不同的事務(wù)傳播屬性,執(zhí)行方法時也會有不同恬总。驗證不同傳播屬性對事務(wù)的影響:
方法一 required --- 方法二 required
方法一 required --- 方法二 requires_new
方法一 required --- 方法二 nested (當(dāng)前存在事務(wù) 則嵌套在事務(wù)內(nèi)執(zhí)行前普,沒有事務(wù)則新開啟一個事務(wù))
具體代碼 主要集中在 AbstractPlatformTransactionManager

典型的模板方法的設(shè)計模式, 子類調(diào)用父類的 getTransaction(),這個方法時不能不能不重寫的方法壹堰,子類只能重寫里面的 doGetTransaction() 封裝事務(wù)對象拭卿,isExistingTransaction():判斷是否存在事務(wù),handleExistingTransaction():存在事務(wù)的處理流程,doBegin():開啟事務(wù)。doCommit():提交事務(wù)贱纠,doRollback():回滾事務(wù)峻厚。


image.png
        @Override
    public final TransactionStatus getTransaction(@Nullable TransactionDefinition definition) throws TransactionException {
                //獲取事務(wù)對象 TransactionObject 由子類去實現(xiàn)
        Object transaction = doGetTransaction();

        if (definition == null) {
            // Use defaults if no transaction definition given.
            definition = new DefaultTransactionDefinition();
        }
      if (isExistingTransaction(transaction)) {//是否存在事務(wù)
            //存在事務(wù)如何處理
            return handleExistingTransaction(definition, transaction, debugEnabled);
        }
    
        // 不存在事務(wù)檢查事務(wù)傳播行為
        if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_MANDATORY) {
            throw new IllegalTransactionStateException(
                    "No existing transaction found for transaction marked with propagation 'mandatory'");
        }
        else if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRED ||
                definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW ||
                definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {
            SuspendedResourcesHolder suspendedResources = suspend(null);
            try {

//封裝: DefaultTransactionStatus : 1事務(wù)對象 2是否是新事務(wù) 3 事務(wù)同步器是否開啟默認是開著的 4 是否 開啟只讀控制。 5 掛起的資源  
                DefaultTransactionStatus status = newTransactionStatus(
                        definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);
                                //開啟事務(wù)
                doBegin(transaction, definition);
                prepareSynchronization(status, definition);
                return status;
            }
            catch (RuntimeException | Error ex) {
                resume(null, suspendedResources);
                throw ex;
            }
        }
        else {
            // 傳播行為 為其他的時候就不做任何處理谆焊,也要封裝一個 TransactionStatus對象
            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);
        }
    }

具體執(zhí)行流程如下圖所示:

SptingTransation.png

獲取事務(wù)對象:

    @Override
    protected Object doGetTransaction() {
                // 每來一個事務(wù)時都要創(chuàng)建一個事務(wù)對象
        DataSourceTransactionObject txObject = new DataSourceTransactionObject();
        txObject.setSavepointAllowed(isNestedTransactionAllowed());
        ConnectionHolder conHolder =
              //從當(dāng)前ThreadLocal (TransactionSynchronizationManager) 中獲取一個連接 并放到事務(wù)對象惠桃。
                (ConnectionHolder) TransactionSynchronizationManager.getResource(obtainDataSource());
        txObject.setConnectionHolder(conHolder, false);
        return txObject;
    }

TransactionSynchronizationManager 為了保證多線程下事務(wù)不出現(xiàn)混亂,通過ThreadLocal 來保證線程的同步.

public abstract class TransactionSynchronizationManager {

    private static final Log logger = LogFactory.getLog(TransactionSynchronizationManager.class);

    private static final ThreadLocal<Map<Object, Object>> resources =
            new NamedThreadLocal<>("Transactional resources");

    private static final ThreadLocal<Set<TransactionSynchronization>> synchronizations =
            new NamedThreadLocal<>("Transaction synchronizations");

    private static final ThreadLocal<String> currentTransactionName =
            new NamedThreadLocal<>("Current transaction name");

    private static final ThreadLocal<Boolean> currentTransactionReadOnly =
            new NamedThreadLocal<>("Current transaction read-only status");

    private static final ThreadLocal<Integer> currentTransactionIsolationLevel =
            new NamedThreadLocal<>("Current transaction isolation level");

    private static final ThreadLocal<Boolean> actualTransactionActive =
            new NamedThreadLocal<>("Actual transaction active");

                                                  ···················
}

判斷是否存在事務(wù):

    @Override
    protected boolean isExistingTransaction(Object transaction) {
//判斷事務(wù)對象中是否存在連接持有器辖试,連接持有器中的事務(wù)是否被激活
        DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
        return (txObject.hasConnectionHolder() && txObject.getConnectionHolder().isTransactionActive());
    }

對掛起事務(wù)的恢復(fù)

    protected final void resume(@Nullable Object transaction, @Nullable SuspendedResourcesHolder resourcesHolder)
            throws TransactionException {

        if (resourcesHolder != null) {
            Object suspendedResources = resourcesHolder.suspendedResources;
            if (suspendedResources != null) {
                doResume(transaction, suspendedResources);
            }
            List<TransactionSynchronization> suspendedSynchronizations = resourcesHolder.suspendedSynchronizations;
            if (suspendedSynchronizations != null) {
                TransactionSynchronizationManager.setActualTransactionActive(resourcesHolder.wasActive);
                TransactionSynchronizationManager.setCurrentTransactionIsolationLevel(resourcesHolder.isolationLevel);
                TransactionSynchronizationManager.setCurrentTransactionReadOnly(resourcesHolder.readOnly);
                TransactionSynchronizationManager.setCurrentTransactionName(resourcesHolder.name);
                doResumeSynchronization(suspendedSynchronizations);
            }
        }
    }
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末辜王,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子罐孝,更是在濱河造成了極大的恐慌呐馆,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,366評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件莲兢,死亡現(xiàn)場離奇詭異汹来,居然都是意外死亡,警方通過查閱死者的電腦和手機改艇,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,521評論 3 395
  • 文/潘曉璐 我一進店門俗慈,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人遣耍,你說我怎么就攤上這事闺阱。” “怎么了舵变?”我有些...
    開封第一講書人閱讀 165,689評論 0 356
  • 文/不壞的土叔 我叫張陵酣溃,是天一觀的道長。 經(jīng)常有香客問我纪隙,道長赊豌,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,925評論 1 295
  • 正文 為了忘掉前任绵咱,我火速辦了婚禮碘饼,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己艾恼,他們只是感情好住涉,可當(dāng)我...
    茶點故事閱讀 67,942評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著钠绍,像睡著了一般舆声。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上柳爽,一...
    開封第一講書人閱讀 51,727評論 1 305
  • 那天媳握,我揣著相機與錄音,去河邊找鬼磷脯。 笑死蛾找,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的赵誓。 我是一名探鬼主播腋粥,決...
    沈念sama閱讀 40,447評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼架曹!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起闹瞧,我...
    開封第一講書人閱讀 39,349評論 0 276
  • 序言:老撾萬榮一對情侶失蹤绑雄,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后奥邮,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體万牺,經(jīng)...
    沈念sama閱讀 45,820評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,990評論 3 337
  • 正文 我和宋清朗相戀三年洽腺,在試婚紗的時候發(fā)現(xiàn)自己被綠了脚粟。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,127評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡蘸朋,死狀恐怖核无,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情藕坯,我是刑警寧澤团南,帶...
    沈念sama閱讀 35,812評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站炼彪,受9級特大地震影響吐根,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜辐马,卻給世界環(huán)境...
    茶點故事閱讀 41,471評論 3 331
  • 文/蒙蒙 一拷橘、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦冗疮、人聲如沸萄唇。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,017評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽穷绵。三九已至,卻和暖如春特愿,著一層夾襖步出監(jiān)牢的瞬間仲墨,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,142評論 1 272
  • 我被黑心中介騙來泰國打工揍障, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留目养,地道東北人。 一個月前我還...
    沈念sama閱讀 48,388評論 3 373
  • 正文 我出身青樓毒嫡,卻偏偏與公主長得像癌蚁,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子兜畸,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,066評論 2 355

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