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

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

Spring進(jìn)行了統(tǒng)一的抽象,形成了PlatformTransactionManager事務(wù)管理器接口,事務(wù)的提交、回滾等操作全部交給它來實現(xiàn)。

Spring的事務(wù)體系也是在PlatformTransactionManager事務(wù)管理器接口上開展開來的(不管是JPA還是JDBC等都實現(xiàn)自接口 PlatformTransactionManager 如果你添加的是 spring-boot-starter-jdbc 依賴,框架會默認(rèn)注入 DataSourceTransactionManager實例。如果你添加的是 spring-boot-starter-data-jpa 依賴,框架會默認(rèn)注入 JpaTransactionManager 實例。,所以先來了解下PlatformTransactionManager事務(wù)管理器。

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

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

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

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

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

一. 看下PlatformTransactionManager如何來操作事務(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ù)的隔離級別、事務(wù)的傳播屬性、超時時間設(shè)置、是否只讀
    1. 紅線上方是些常量定義,關(guān)于常量定義(事務(wù)的隔離級別和事務(wù)的傳播屬性等等) 具體事務(wù)常量定義
這里我們要明白的地方:

事務(wù)的隔離級別是數(shù)據(jù)庫本身的事務(wù)功能,我們只是基于對數(shù)據(jù)庫的Connection,對書屋操作做封裝,而事務(wù)的傳播屬性則是Spring自己為我們提供的功能,數(shù)據(jù)庫事務(wù)沒有事務(wù)的傳播屬性這一說法。

DefaultTransactionDefinitio實現(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,如果存在一個事務(wù),則支持當(dāng)前事務(wù)。如果沒有事務(wù)則開啟一個新的事務(wù)。被設(shè)置成這個級別時,會為每一個被調(diào)用的方法創(chuàng)建一個邏輯事務(wù)域。如果前面的方法已經(jīng)創(chuàng)建了事務(wù),那么后面的方法支持當(dāng)前的事務(wù),如果當(dāng)前沒有事務(wù)會重新建立事務(wù),其他請看事務(wù)的傳播屬性
  • 事務(wù)的隔離級別 采用底層數(shù)據(jù)庫默認(rèn)的隔離級別
  • 超時時間 采用底層數(shù)據(jù)庫默認(rèn)的超時時間
  • 是否只讀為false

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

先引出Connection連接中的保存點功能:

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

TransactionStatus它繼承了SavepointManager接口,SavepointManager是對事務(wù)中上述保存點功能的封裝,如下:

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

Spring利用保存點功能實現(xiàn)了事務(wù)的嵌套功能。后面會詳細(xì)說明。

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

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

常用的TransactionStatus接口實現(xiàn)為DefaultTransactionStatus,真正用來操作事務(wù)的

目前jdbc事務(wù)是通過Connection來實現(xiàn)事務(wù)的,Hibernate是通過它自己定義的Transaction來實現(xiàn)的,所以各家的事務(wù)都不同,所以

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

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

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

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

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

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

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

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

重點來說下

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

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

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

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

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

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

    從當(dāng)前線程中獲取綁定的ConnectionHolder,可能為null,如果為null,則會在下一個開
    啟事務(wù)的過程中,從dataSource中獲取一個Connection,封裝成ConnectionHolder,然后再綁定到當(dāng)前線程

    然后我們new 一個DataSourceTransactionObject了,具體過程如下:

構(gòu)建DefaultTransactionStatus,使用Object transaction開啟事務(wù)

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

因為開啟了一個事務(wù),則必須要關(guān)閉DataSourceTransactionObject中Connection的自動提交,代碼如下(省略一些):

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);
 
        //取消自動提交
        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());
        }
    }

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

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

DataSourceTransactionManager就是使用DataSourceTransactionObject中的Connection來進(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);
    }
}

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

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

這里對于使用提供一個小demo

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

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

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

事務(wù)的失效場景

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

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

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

友情鏈接更多精彩內(nèi)容