詳解Spring的事務(wù)管理PlatformTransactionManager

常規(guī)的事務(wù)大致有許多種,比如jdbc事務(wù), Hibernate的事務(wù), JpaTransactionObject事務(wù)
關(guān)于他們的對(duì)比可以看看事務(wù)比較
我們直接看PlatformTransactionManager

Spring進(jìn)行了統(tǒng)一的抽象颠毙,形成了PlatformTransactionManager事務(wù)管理器接口甫匹,事務(wù)的提交沽甥、回滾等操作全部交給它來(lái)實(shí)現(xiàn)为严。

Spring的事務(wù)體系也是在PlatformTransactionManager事務(wù)管理器接口上開(kāi)展開(kāi)來(lái)的(不管是JPA還是JDBC等都實(shí)現(xiàn)自接口 PlatformTransactionManager 如果你添加的是 spring-boot-starter-jdbc 依賴澡绩,框架會(huì)默認(rèn)注入 DataSourceTransactionManager實(shí)例豹爹。如果你添加的是 spring-boot-starter-data-jpa 依賴责蝠,框架會(huì)默認(rèn)注入 JpaTransactionManager 實(shí)例党巾。萎庭,所以先來(lái)了解下PlatformTransactionManager事務(wù)管理器。

事務(wù)功能的總體接口設(shè)計(jì)

先來(lái)看下三大接口齿拂,三個(gè)接口功能一句話總的來(lái)說(shuō)事務(wù)管理器基于事務(wù)基礎(chǔ)信息在操作事務(wù)時(shí)候?qū)κ聞?wù)狀態(tài)進(jìn)行更新驳规。

  • PlatformTransactionManager : 事務(wù)管理器

  • TransactionDefinition : 事務(wù)的一些基礎(chǔ)信息,如超時(shí)時(shí)間署海、隔離級(jí)別吗购、傳播屬性等

  • TransactionStatus : 事務(wù)的一些狀態(tài)信息,如是否是一個(gè)新的事務(wù)砸狞、是否已被標(biāo)記為回滾

一. 看下PlatformTransactionManager如何來(lái)操作事務(wù):

public interface PlatformTransactionManager {
 
    //根據(jù)事務(wù)定義TransactionDefinition捻勉,獲取事務(wù)
    TransactionStatus getTransaction(TransactionDefinition definition);
 
    //提交事務(wù)
    void commit(TransactionStatus status);
 
    //回滾事務(wù)
    void rollback(TransactionStatus status);
}

二. 事務(wù)定義接口TransactionDefinition

  • 1.事務(wù)的定義包含:事務(wù)的隔離級(jí)別、事務(wù)的傳播屬性刀森、超時(shí)時(shí)間設(shè)置踱启、是否只讀
    1. 紅線上方是些常量定義,關(guān)于常量定義(事務(wù)的隔離級(jí)別和事務(wù)的傳播屬性等等) 具體事務(wù)常量定義
這里我們要明白的地方:

事務(wù)的隔離級(jí)別是數(shù)據(jù)庫(kù)本身的事務(wù)功能,我們只是基于對(duì)數(shù)據(jù)庫(kù)的Connection撒强,對(duì)書(shū)屋操作做封裝禽捆,而事務(wù)的傳播屬性則是Spring自己為我們提供的功能,數(shù)據(jù)庫(kù)事務(wù)沒(méi)有事務(wù)的傳播屬性這一說(shuō)法飘哨。

DefaultTransactionDefinitio實(shí)現(xiàn)了該接口(TransactionDefinition):進(jìn)行了一些默認(rèn)的事務(wù)定義
public class DefaultTransactionDefinition implements TransactionDefinition, Serializable {
    private int propagationBehavior = PROPAGATION_REQUIRED;
    private int isolationLevel = ISOLATION_DEFAULT;
    private int timeout = TIMEOUT_DEFAULT;
    private boolean readOnly = false;
    //略
}
  • 事務(wù)的傳播屬性PROPAGATION_REQUIRED胚想,如果存在一個(gè)事務(wù),則支持當(dāng)前事務(wù)芽隆。如果沒(méi)有事務(wù)則開(kāi)啟一個(gè)新的事務(wù)浊服。被設(shè)置成這個(gè)級(jí)別時(shí),會(huì)為每一個(gè)被調(diào)用的方法創(chuàng)建一個(gè)邏輯事務(wù)域胚吁。如果前面的方法已經(jīng)創(chuàng)建了事務(wù)牙躺,那么后面的方法支持當(dāng)前的事務(wù),如果當(dāng)前沒(méi)有事務(wù)會(huì)重新建立事務(wù),其他請(qǐng)看事務(wù)的傳播屬性
  • 事務(wù)的隔離級(jí)別 采用底層數(shù)據(jù)庫(kù)默認(rèn)的隔離級(jí)別
  • 超時(shí)時(shí)間 采用底層數(shù)據(jù)庫(kù)默認(rèn)的超時(shí)時(shí)間
  • 是否只讀為false

三. 事務(wù)的狀態(tài)信息定義TransactionStatus

先引出Connection連接中的保存點(diǎn)功能:

//創(chuàng)建一個(gè)保存點(diǎn)
conn.setSavepoint(name);
//回滾到某個(gè)保存點(diǎn)
conn.rollback(savepoint);
//釋放某個(gè)保存點(diǎn)
conn.releaseSavepoint(savepoint);

TransactionStatus它繼承了SavepointManager接口腕扶,SavepointManager是對(duì)事務(wù)中上述保存點(diǎn)功能的封裝孽拷,如下:

public interface SavepointManager {
    Object createSavepoint() throws TransactionException;
    void rollbackToSavepoint(Object savepoint) throws TransactionException;
    void releaseSavepoint(Object savepoint) throws TransactionException;
}

Spring利用保存點(diǎn)功能實(shí)現(xiàn)了事務(wù)的嵌套功能。后面會(huì)詳細(xì)說(shuō)明半抱。

至于我們說(shuō)的TransactionStatus本身更多存儲(chǔ)的是事務(wù)的一些狀態(tài)信息:

  • 是否是一個(gè)新的事物
  • 是否有保存點(diǎn)
  • 是否已被標(biāo)記為回滾

常用的TransactionStatus接口實(shí)現(xiàn)為DefaultTransactionStatus脓恕,真正用來(lái)操作事務(wù)的

目前jdbc事務(wù)是通過(guò)Connection來(lái)實(shí)現(xiàn)事務(wù)的,Hibernate是通過(guò)它自己定義的Transaction來(lái)實(shí)現(xiàn)的窿侈,所以各家的事務(wù)都不同炼幔,所以

Spring只能以O(shè)bject transaction的形式來(lái)表示各家的事務(wù),事務(wù)的回滾和提交等操作都會(huì)最終委托給上Object transaction來(lái)完成史简。

Object transaction的職責(zé)就是提交回滾事務(wù)乃秀,這個(gè)transaction的選擇可能如下:

  • DataSourceTransactionObject
  • HibernateTransactionObject
  • JpaTransactionObject(之后再詳細(xì)說(shuō))

詳細(xì)信息分別如下:

  • 對(duì)于DataSourceTransactionObject:
    我們使用了dataSource來(lái)獲取連接,要想實(shí)現(xiàn)事務(wù)功能,必然需要使用Connection跺讯,所以它中肯定有一個(gè)Connection來(lái)執(zhí)行事務(wù)的操作枢贿。
    DataSourceTransactionObject中有一個(gè)ConnectionHolder,它封裝了一個(gè)Connection抬吟。

  • 對(duì)于HibernateTransactionObject:
    我們使用了hibenrate,此時(shí)要想實(shí)現(xiàn)事務(wù)功能萨咕,必然需要通過(guò)hibernate自己定義的Transaction來(lái)實(shí)現(xiàn)。
    HibernateTransactionObject中含有一個(gè)SessionHolder火本,和上面的ConnectionHolder一樣,它封裝了一個(gè)Session,有了Session,我們就可以通過(guò)Session來(lái)產(chǎn)生一個(gè)Hibernate的Transaction,從而實(shí)現(xiàn)事務(wù)操作囱淋。

四. 事務(wù)管理器接口定義PlatformTransactionManager

類圖關(guān)系如下:

重點(diǎn)來(lái)說(shuō)下

  • AbstractPlatformTransactionManager
    • DataSourceTransactionManager
    • HibernateTransactionManager
    • JpaTransactionManager(之后詳細(xì)再說(shuō))

這就需要來(lái)看看事務(wù)管理器的接口建炫,上述的他們都是怎么實(shí)現(xiàn)的:

  • 1 第一個(gè)接口:TransactionStatus getTransaction(TransactionDefinition definition) 根據(jù)事務(wù)定義獲取事務(wù)狀態(tài)

    大體內(nèi)容就是先獲取上述說(shuō)明的Object transaction,判斷當(dāng)前事務(wù)是否已存在幸海,如果存在則進(jìn)行事務(wù)的傳播屬性處理,后面詳細(xì)說(shuō)明,如果不存在new DefaultTransactionStatus揍魂,新創(chuàng)建一個(gè)事務(wù),同時(shí)使用Object transaction開(kāi)啟事務(wù)棚瘟。 分成了幾個(gè)過(guò)程:

    不同的事務(wù)管理器獲取不同的Object transaction

    • Spring獲取Object transaction:
      DataSourceTransactionManager就是獲取上述的DataSourceTransactionObject

    從當(dāng)前線程中獲取綁定的ConnectionHolder现斋,可能為null,如果為null,則會(huì)在下一個(gè)開(kāi)
    啟事務(wù)的過(guò)程中偎蘸,從dataSource中獲取一個(gè)Connection庄蹋,封裝成ConnectionHolder,然后再綁定到當(dāng)前線程

    然后我們new 一個(gè)DataSourceTransactionObject了迷雪,具體過(guò)程如下:

構(gòu)建DefaultTransactionStatus限书,使用Object transaction開(kāi)啟事務(wù)

DataSourceTransactionManager的DataSourceTransactionObject開(kāi)啟過(guò)程如下:
首先判斷之前的獲取當(dāng)前線程綁定的ConnectionHolder是否為null,如果為null章咧,從dataSource中獲取一個(gè)Connection倦西,封裝成ConnectionHolder,然后再綁定到當(dāng)前線程(通過(guò)ThreadLocal來(lái)實(shí)現(xiàn)赁严,可以看我別的文章)

因?yàn)?strong>開(kāi)啟了一個(gè)事務(wù)扰柠,則必須要關(guān)閉DataSourceTransactionObject中Connection的自動(dòng)提交,代碼如下(省略一些):

protected void doBegin(Object transaction, TransactionDefinition definition) {
        DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
        Connection con = null;
 
        //如果ConnectionHolder是否為null误澳,從新獲取
        if (txObject.getConnectionHolder() == null ||
                txObject.getConnectionHolder().isSynchronizedWithTransaction()) {
            Connection newCon = this.dataSource.getConnection();
            txObject.setConnectionHolder(new ConnectionHolder(newCon), true);
        }
        con = txObject.getConnectionHolder().getConnection();
 
        Integer previousIsolationLevel = DataSourceUtils.prepareConnectionForTransaction(con, definition);
        txObject.setPreviousIsolationLevel(previousIsolationLevel);
 
        //取消自動(dòng)提交
        if (con.getAutoCommit()) {
            txObject.setMustRestoreAutoCommit(true);
            if (logger.isDebugEnabled()) {
                logger.debug("Switching JDBC Connection [" + con + "] to manual commit");
            }
            con.setAutoCommit(false);
        }
        txObject.getConnectionHolder().setTransactionActive(true);
 
 
        //如果是新增的ConnectionHolder耻矮,則綁定到當(dāng)前線程
        if (txObject.isNewConnectionHolder()) {
            TransactionSynchronizationManager.bindResource(getDataSource(), txObject.getConnectionHolder());
        }
    }

第二個(gè)接口:void rollback(TransactionStatus status) 回滾事務(wù)

回滾,則還是利用DefaultTransactionStatus內(nèi)部的Object transaction來(lái)執(zhí)行回滾操作

DataSourceTransactionManager就是使用DataSourceTransactionObject中的Connection來(lái)進(jìn)行回滾操作

protected void doRollback(DefaultTransactionStatus status) {
    DataSourceTransactionObject txObject = (DataSourceTransactionObject) status.getTransaction();
    Connection con = txObject.getConnectionHolder().getConnection();
    try {
        con.rollback();
    }
    catch (SQLException ex) {
        throw new TransactionSystemException("Could not roll back JDBC transaction", ex);
    }
}

第三個(gè)接口: void commit(TransactionStatus status) 提交事務(wù)

同理忆谓,DataSourceTransactionManager依托內(nèi)部的Connection來(lái)完成提交操作

這里對(duì)于使用提供一個(gè)小demo

比如我們現(xiàn)在涉及到一個(gè)付款成功的業(yè)務(wù),涉及到數(shù)據(jù)庫(kù)金額更新和數(shù)據(jù)庫(kù)訂單狀態(tài)數(shù)據(jù)更新,那么前端發(fā)送一個(gè)請(qǐng)求到我們的controller,我們?cè)赾ontroller做向上反饋,在service做事務(wù)管理的業(yè)務(wù)操作以及數(shù)據(jù)庫(kù)操作

@PostMapping("moneyOperation")
    public String moneyOperation() {
        if (transactionOperation.moneyOperation()) {
            return "付款成功";
        }
        else {
            return "付款失旕勺啊!";
        }
    }
/**
 * @description: money相關(guān)事務(wù)demo
 * @author: zyh
 * @create: 2021-06-23 14:06
 **/
@Service
@Slf4j
@RequiredArgsConstructor
public class TransactionOperation {
    private final PlatformTransactionManager transactionManager;


    public boolean moneyOperation() {
        TransactionStatus status;
        // 手動(dòng)開(kāi)啟事務(wù)初始化
        status = transactionManager.getTransaction(new DefaultTransactionDefinition());
        //操作
        try {
            // 數(shù)據(jù)庫(kù)操作后(例如業(yè)務(wù)上需先更新金額,再更新訂單信息)
            moneyDaoOperation();
            DefaultTransactionDefinition
            // 操作無(wú)異常:提交事務(wù)
            transactionManager.commit(status);
            log.debug("操作xxxx成功");
            return true;
        } catch (Exception e) {
            log.debug("操作xxxx成功出錯(cuò),正在回滾,錯(cuò)誤信息為:"+e.getMessage());
            // 捕獲異常, 事務(wù)回滾
            transactionManager.rollback(status);
            log.debug("操作xxxx已回滾");
            return false;
        }
    }
}

參考https://blog.csdn.net/luzhensmart/article/details/90167871
``

事務(wù)的失效場(chǎng)景

https://mp.weixin.qq.com/s/wrs5rUlFKdemU6m_QUYCZg

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末哨免,一起剝皮案震驚了整個(gè)濱河市茎活,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌琢唾,老刑警劉巖载荔,帶你破解...
    沈念sama閱讀 221,576評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異采桃,居然都是意外死亡懒熙,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,515評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門(mén)普办,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)工扎,“玉大人,你說(shuō)我怎么就攤上這事衔蹲≈铮” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 168,017評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵舆驶,是天一觀的道長(zhǎng)橱健。 經(jīng)常有香客問(wèn)我,道長(zhǎng)沙廉,這世上最難降的妖魔是什么拘荡? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 59,626評(píng)論 1 296
  • 正文 為了忘掉前任,我火速辦了婚禮蓝仲,結(jié)果婚禮上俱病,老公的妹妹穿的比我還像新娘。我一直安慰自己袱结,他們只是感情好亮隙,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,625評(píng)論 6 397
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著垢夹,像睡著了一般溢吻。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上果元,一...
    開(kāi)封第一講書(shū)人閱讀 52,255評(píng)論 1 308
  • 那天促王,我揣著相機(jī)與錄音,去河邊找鬼而晒。 笑死蝇狼,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的倡怎。 我是一名探鬼主播迅耘,決...
    沈念sama閱讀 40,825評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼贱枣,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了颤专?” 一聲冷哼從身側(cè)響起纽哥,我...
    開(kāi)封第一講書(shū)人閱讀 39,729評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎栖秕,沒(méi)想到半個(gè)月后春塌,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,271評(píng)論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡簇捍,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,363評(píng)論 3 340
  • 正文 我和宋清朗相戀三年只壳,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片暑塑。...
    茶點(diǎn)故事閱讀 40,498評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡吕世,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出梯投,到底是詐尸還是另有隱情,我是刑警寧澤况毅,帶...
    沈念sama閱讀 36,183評(píng)論 5 350
  • 正文 年R本政府宣布分蓖,位于F島的核電站,受9級(jí)特大地震影響尔许,放射性物質(zhì)發(fā)生泄漏么鹤。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,867評(píng)論 3 333
  • 文/蒙蒙 一味廊、第九天 我趴在偏房一處隱蔽的房頂上張望蒸甜。 院中可真熱鬧,春花似錦余佛、人聲如沸柠新。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,338評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)恨憎。三九已至,卻和暖如春郊楣,著一層夾襖步出監(jiān)牢的瞬間憔恳,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,458評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工净蚤, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留钥组,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,906評(píng)論 3 376
  • 正文 我出身青樓今瀑,卻偏偏與公主長(zhǎng)得像程梦,于是被迫代替她去往敵國(guó)和親点把。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,507評(píng)論 2 359

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

  • 事務(wù)是一組操作的原子執(zhí)行作烟,其中任何一筆操作失敗將導(dǎo)致全部操作撤銷愉粤。 什么是事務(wù)? 如上所言,事務(wù)遵循ACID原則拿撩,...
    點(diǎn)融黑幫閱讀 7,812評(píng)論 3 36
  • PartV.TransactiomManagement github 地址 https://github.com/...
    天幕_bc1a閱讀 1,127評(píng)論 2 0
  • Spring事務(wù)_事務(wù)管理的支持-04 Spring 為事務(wù)管理提供一致的編程模板衣厘,在高層次建立統(tǒng)一的事務(wù)抽象。不...
    老貓頭閱讀 610評(píng)論 0 1
  • 1.數(shù)據(jù)庫(kù)事務(wù)基礎(chǔ)知識(shí) 1.1.何為數(shù)據(jù)庫(kù)事務(wù) 數(shù)據(jù)庫(kù)事務(wù)的4個(gè)特性 原子性:組成一個(gè)事務(wù)的多個(gè)數(shù)據(jù)庫(kù)操作是一個(gè)不...
    小螺釘12138閱讀 1,581評(píng)論 1 18
  • Spring事務(wù)概述 JAVA事務(wù)局限 局部事務(wù)的管理綁定到了具體的數(shù)據(jù)訪問(wèn)方式使用特定的數(shù)據(jù)訪問(wèn)方式压恒,就必須使用...
    坑的就是我們家閱讀 418評(píng)論 0 0