溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

Spring事務(wù)管理的詳細(xì)介紹

發(fā)布時(shí)間:2021-09-13 11:04:41 來源:億速云 閱讀:98 作者:chen 欄目:編程語言

本篇內(nèi)容主要講解“Spring事務(wù)管理的詳細(xì)介紹”,感興趣的朋友不妨來看看。本文介紹的方法操作簡(jiǎn)單快捷,實(shí)用性強(qiáng)。下面就讓小編來帶大家學(xué)習(xí)“Spring事務(wù)管理的詳細(xì)介紹”吧!

事務(wù)概念回顧

什么是事務(wù)?

事務(wù)是邏輯上的一組操作,要么都執(zhí)行,要么都不執(zhí)行.

事物的特性(ACID):

Spring事務(wù)管理的詳細(xì)介紹

  1. 原子性: 事務(wù)是最小的執(zhí)行單位,不允許分割。事務(wù)的原子性確保動(dòng)作要么全部完成,要么完全不起作用;

  2. 一致性: 執(zhí)行事務(wù)前后,數(shù)據(jù)保持一致;

  3. 隔離性: 并發(fā)訪問數(shù)據(jù)庫時(shí),一個(gè)用戶的事物不被其他事物所干擾,各并發(fā)事務(wù)之間數(shù)據(jù)庫是獨(dú)立的;

  4. 持久性: 一個(gè)事務(wù)被提交之后。它對(duì)數(shù)據(jù)庫中數(shù)據(jù)的改變是持久的,即使數(shù)據(jù)庫發(fā)生故障也不應(yīng)該對(duì)其有任何影響。

Spring事務(wù)管理接口介紹

Spring事務(wù)管理接口:

  • PlatformTransactionManager: (平臺(tái))事務(wù)管理器

  • TransactionDefinition: 事務(wù)定義信息(事務(wù)隔離級(jí)別、傳播行為、超時(shí)、只讀、回滾規(guī)則)

  • TransactionStatus: 事務(wù)運(yùn)行狀態(tài)

所謂事務(wù)管理,其實(shí)就是“按照給定的事務(wù)規(guī)則來執(zhí)行提交或者回滾操作”。

PlatformTransactionManager接口介紹

Spring并不直接管理事務(wù),而是提供了多種事務(wù)管理器 ,他們將事務(wù)管理的職責(zé)委托給Hibernate或者JTA等持久化機(jī)制所提供的相關(guān)平臺(tái)框架的事務(wù)來實(shí)現(xiàn)。 Spring事務(wù)管理器的接口是: org.springframework.transaction.PlatformTransactionManager ,通過這個(gè)接口,Spring為各個(gè)平臺(tái)如JDBC、Hibernate等都提供了對(duì)應(yīng)的事務(wù)管理器,但是具體的實(shí)現(xiàn)就是各個(gè)平臺(tái)自己的事情了。

PlatformTransactionManager接口代碼如下:

PlatformTransactionManager接口中定義了三個(gè)方法:

Public interface PlatformTransactionManager()...{ 
 // Return a currently active transaction or create a new one, according to the specified propagation behavior(根據(jù)指定的傳播行為,返回當(dāng)前活動(dòng)的事務(wù)或創(chuàng)建一個(gè)新事務(wù)。)
 TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException; 
 // Commit the given transaction, with regard to its status(使用事務(wù)目前的狀態(tài)提交事務(wù))
 Void commit(TransactionStatus status) throws TransactionException; 
 // Perform a rollback of the given transaction(對(duì)執(zhí)行的事務(wù)進(jìn)行回滾)
 Void rollback(TransactionStatus status) throws TransactionException; 
 }

我們剛剛也說了Spring中PlatformTransactionManager根據(jù)不同持久層框架所對(duì)應(yīng)的接口實(shí)現(xiàn)類,幾個(gè)比較常見的如下圖所示

Spring事務(wù)管理的詳細(xì)介紹

比如我們?cè)谑褂肑DBC或者iBatis(就是Mybatis)進(jìn)行數(shù)據(jù)持久化操作時(shí),我們的xml配置通常如下:

    <!-- 事務(wù)管理器 -->
    <bean id="transactionManager"
        class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <!-- 數(shù)據(jù)源 -->
        <property name="dataSource" ref="dataSource" />
    </bean>

TransactionDefinition接口介紹

事務(wù)管理器接口 PlatformTransactionManager 通過 getTransaction(TransactionDefinition definition) 方法來得到一個(gè)事務(wù),這個(gè)方法里面的參數(shù)是 TransactionDefinition類 ,這個(gè)類就定義了一些基本的事務(wù)屬性。

那么什么是事務(wù)屬性呢?

事務(wù)屬性可以理解成事務(wù)的一些基本配置,描述了事務(wù)策略如何應(yīng)用到方法上。事務(wù)屬性包含了5個(gè)方面。

Spring事務(wù)管理的詳細(xì)介紹

TransactionDefinition接口中的方法如下:

TransactionDefinition接口中定義了5個(gè)方法以及一些表示事務(wù)屬性的常量比如隔離級(jí)別、傳播行為等等的常量。

我下面只是列出了TransactionDefinition接口中的方法而沒有給出接口中定義的常量,該接口中的常量信息會(huì)在后面依次介紹到。

public interface TransactionDefinition {
 // 返回事務(wù)的傳播行為
 int getPropagationBehavior(); 
 // 返回事務(wù)的隔離級(jí)別,事務(wù)管理器根據(jù)它來控制另外一個(gè)事務(wù)可以看到本事務(wù)內(nèi)的哪些數(shù)據(jù)
 int getIsolationLevel(); 
 // 返回事務(wù)必須在多少秒內(nèi)完成
 //返回事務(wù)的名字
 String getName();
 int getTimeout(); 
 // 返回是否優(yōu)化為只讀事務(wù)。
 boolean isReadOnly();
}

(1)事務(wù)隔離級(jí)別(定義了一個(gè)事務(wù)可能受其他并發(fā)事務(wù)影響的程度):

我們先來看一下 并發(fā)事務(wù)帶來的問題 ,然后再來介紹一下 TransactionDefinition 接口 中定義了五個(gè)表示隔離級(jí)別的常量。

并發(fā)事務(wù)帶來的問題

在典型的應(yīng)用程序中,多個(gè)事務(wù)并發(fā)運(yùn)行,經(jīng)常會(huì)操作相同的數(shù)據(jù)來完成各自的任務(wù)(多個(gè)用戶對(duì)統(tǒng)一數(shù)據(jù)進(jìn)行操作)。并發(fā)雖然是必須的,但可能會(huì)導(dǎo)致一下的問題。

  • 臟讀(Dirty read): 當(dāng)一個(gè)事務(wù)正在訪問數(shù)據(jù)并且對(duì)數(shù)據(jù)進(jìn)行了修改,而這種修改還沒有提交到數(shù)據(jù)庫中,這時(shí)另外一個(gè)事務(wù)也訪問了這個(gè)數(shù)據(jù),然后使用了這個(gè)數(shù)據(jù)。因?yàn)檫@個(gè)數(shù)據(jù)是還沒有提交的數(shù)據(jù),那么另外一個(gè)事務(wù)讀到的這個(gè)數(shù)據(jù)是“臟數(shù)據(jù)”,依據(jù)“臟數(shù)據(jù)”所做的操作可能是不正確的。

  • 丟失修改(Lost to modify): 指在一個(gè)事務(wù)讀取一個(gè)數(shù)據(jù)時(shí),另外一個(gè)事務(wù)也訪問了該數(shù)據(jù),那么在第一個(gè)事務(wù)中修改了這個(gè)數(shù)據(jù)后,第二個(gè)事務(wù)也修改了這個(gè)數(shù)據(jù)。這樣第一個(gè)事務(wù)內(nèi)的修改結(jié)果就被丟失,因此稱為丟失修改。

  • 例如:事務(wù)1讀取某表中的數(shù)據(jù)A=20,事務(wù)2也讀取A=20,事務(wù)1修改A=A-1,事務(wù)2也修改A=A-1,最終結(jié)果A=19,事務(wù)1的修改被丟失。

  • 不可重復(fù)讀(Unrepeatableread): 指在一個(gè)事務(wù)內(nèi)多次讀同一數(shù)據(jù)。在這個(gè)事務(wù)還沒有結(jié)束時(shí),另一個(gè)事務(wù)也訪問該數(shù)據(jù)。那么,在第一個(gè)事務(wù)中的兩次讀數(shù)據(jù)之間,由于第二個(gè)事務(wù)的修改導(dǎo)致第一個(gè)事務(wù)兩次讀取的數(shù)據(jù)可能不太一樣。這就發(fā)生了在一個(gè)事務(wù)內(nèi)兩次讀到的數(shù)據(jù)是不一樣的情況,因此稱為不可重復(fù)讀。

  • 幻讀(Phantom read): 幻讀與不可重復(fù)讀類似。它發(fā)生在一個(gè)事務(wù)(T1)讀取了幾行數(shù)據(jù),接著另一個(gè)并發(fā)事務(wù)(T2)插入了一些數(shù)據(jù)時(shí)。在隨后的查詢中,第一個(gè)事務(wù)(T1)就會(huì)發(fā)現(xiàn)多了一些原本不存在的記錄,就好像發(fā)生了幻覺一樣,所以稱為幻讀。

不可重復(fù)度和幻讀區(qū)別:

不可重復(fù)讀的重點(diǎn)是修改,幻讀的重點(diǎn)在于新增或者刪除。

例1(同樣的條件, 你讀取過的數(shù)據(jù), 再次讀取出來發(fā)現(xiàn)值不一樣了 ):事務(wù)1中的A先生讀取自己的工資為 1000的操作還沒完成,事務(wù)2中的B先生就修改了A的工資為2000,導(dǎo) 致A再讀自己的工資時(shí)工資變?yōu)?2000;這就是不可重復(fù)讀。

例2(同樣的條件, 第1次和第2次讀出來的記錄數(shù)不一樣 ):假某工資單表中工資大于3000的有4人,事務(wù)1讀取了所有工資大于3000的人,共查到4條記錄,這時(shí)事務(wù)2 又插入了一條工資大于3000的記錄,事務(wù)1再次讀取時(shí)查到的記錄就變?yōu)榱?條,這樣就導(dǎo)致了幻讀。

隔離級(jí)別

TransactionDefinition 接口中定義了五個(gè)表示隔離級(jí)別的常量:

  • TransactionDefinition.ISOLATION_DEFAULT:使用后端數(shù)據(jù)庫默認(rèn)的隔離級(jí)別,Mysql 默認(rèn)采用的 REPEATABLE_READ隔離級(jí)別 Oracle 默認(rèn)采用的 READ_COMMITTED隔離級(jí)別.

  • TransactionDefinition.ISOLATION_READ_UNCOMMITTED: 最低的隔離級(jí)別,允許讀取尚未提交的數(shù)據(jù)變更,可能會(huì)導(dǎo)致臟讀、幻讀或不可重復(fù)讀

  • TransactionDefinition.ISOLATION_READ_COMMITTED: 允許讀取并發(fā)事務(wù)已經(jīng)提交的數(shù)據(jù),可以阻止臟讀,但是幻讀或不可重復(fù)讀仍有可能發(fā)生

  • TransactionDefinition.ISOLATION_REPEATABLE_READ: 對(duì)同一字段的多次讀取結(jié)果都是一致的,除非數(shù)據(jù)是被本身事務(wù)自己所修改,可以阻止臟讀和不可重復(fù)讀,但幻讀仍有可能發(fā)生。

  • TransactionDefinition.ISOLATION_SERIALIZABLE: 最高的隔離級(jí)別,完全服從ACID的隔離級(jí)別。所有的事務(wù)依次逐個(gè)執(zhí)行,這樣事務(wù)之間就完全不可能產(chǎn)生干擾,也就是說,該級(jí)別可以防止臟讀、不可重復(fù)讀以及幻讀。但是這將嚴(yán)重影響程序的性能。通常情況下也不會(huì)用到該級(jí)別。

(2)事務(wù)傳播行為(為了解決業(yè)務(wù)層方法之間互相調(diào)用的事務(wù)問題):

當(dāng)事務(wù)方法被另一個(gè)事務(wù)方法調(diào)用時(shí),必須指定事務(wù)應(yīng)該如何傳播。例如:方法可能繼續(xù)在現(xiàn)有事務(wù)中運(yùn)行,也可能開啟一個(gè)新事務(wù),并在自己的事務(wù)中運(yùn)行。在TransactionDefinition定義中包括了如下幾個(gè)表示傳播行為的常量:

支持當(dāng)前事務(wù)的情況:

  • TransactionDefinition.PROPAGATION_REQUIRED: 如果當(dāng)前存在事務(wù),則加入該事務(wù);如果當(dāng)前沒有事務(wù),則創(chuàng)建一個(gè)新的事務(wù)。

  • TransactionDefinition.PROPAGATION_SUPPORTS: 如果當(dāng)前存在事務(wù),則加入該事務(wù);如果當(dāng)前沒有事務(wù),則以非事務(wù)的方式繼續(xù)運(yùn)行。

  • TransactionDefinition.PROPAGATION_MANDATORY: 如果當(dāng)前存在事務(wù),則加入該事務(wù);如果當(dāng)前沒有事務(wù),則拋出異常。(mandatory:強(qiáng)制性)

不支持當(dāng)前事務(wù)的情況:

  • TransactionDefinition.PROPAGATION_REQUIRES_NEW: 創(chuàng)建一個(gè)新的事務(wù),如果當(dāng)前存在事務(wù),則把當(dāng)前事務(wù)掛起。

  • TransactionDefinition.PROPAGATION_NOT_SUPPORTED: 以非事務(wù)方式運(yùn)行,如果當(dāng)前存在事務(wù),則把當(dāng)前事務(wù)掛起。

  • TransactionDefinition.PROPAGATION_NEVER: 以非事務(wù)方式運(yùn)行,如果當(dāng)前存在事務(wù),則拋出異常。

其他情況:

  • TransactionDefinition.PROPAGATION_NESTED: 如果當(dāng)前存在事務(wù),則創(chuàng)建一個(gè)事務(wù)作為當(dāng)前事務(wù)的嵌套事務(wù)來運(yùn)行;如果當(dāng)前沒有事務(wù),則該取值等價(jià)于TransactionDefinition.PROPAGATION_REQUIRED。

這里需要指出的是,前面的六種事務(wù)傳播行為是 Spring 從 EJB 中引入的,他們共享相同的概念。而 PROPAGATION_NESTED 是 Spring 所特有的。以 PROPAGATION_NESTED 啟動(dòng)的事務(wù)內(nèi)嵌于外部事務(wù)中(如果存在外部事務(wù)的話),此時(shí),內(nèi)嵌事務(wù)并不是一個(gè)獨(dú)立的事務(wù),它依賴于外部事務(wù)的存在,只有通過外部的事務(wù)提交,才能引起內(nèi)部事務(wù)的提交,嵌套的子事務(wù)不能單獨(dú)提交。如果熟悉 JDBC 中的保存點(diǎn)(SavePoint)的概念,那嵌套事務(wù)就很容易理解了,其實(shí)嵌套的子事務(wù)就是保存點(diǎn)的一個(gè)應(yīng)用,一個(gè)事務(wù)中可以包括多個(gè)保存點(diǎn),每一個(gè)嵌套子事務(wù)。另外,外部事務(wù)的回滾也會(huì)導(dǎo)致嵌套子事務(wù)的回滾。

(3) 事務(wù)超時(shí)屬性(一個(gè)事務(wù)允許執(zhí)行的最長時(shí)間)

所謂事務(wù)超時(shí),就是指一個(gè)事務(wù)所允許執(zhí)行的最長時(shí)間,如果超過該時(shí)間限制但事務(wù)還沒有完成,則自動(dòng)回滾事務(wù)。在 TransactionDefinition 中以 int 的值來表示超時(shí)時(shí)間,其單位是秒。

(4) 事務(wù)只讀屬性(對(duì)事物資源是否執(zhí)行只讀操作)

事務(wù)的只讀屬性是指,對(duì)事務(wù)性資源進(jìn)行只讀操作或者是讀寫操作。所謂事務(wù)性資源就是指那些被事務(wù)管理的資源,比如數(shù)據(jù)源、 JMS 資源,以及自定義的事務(wù)性資源等等。如果確定只對(duì)事務(wù)性資源進(jìn)行只讀操作,那么我們可以將事務(wù)標(biāo)志為只讀的,以提高事務(wù)處理的性能。在 TransactionDefinition 中以 boolean 類型來表示該事務(wù)是否只讀。

(5) 回滾規(guī)則(定義事務(wù)回滾規(guī)則)

這些規(guī)則定義了哪些異常會(huì)導(dǎo)致事務(wù)回滾而哪些不會(huì)。默認(rèn)情況下,事務(wù)只有遇到運(yùn)行期異常時(shí)才會(huì)回滾,而在遇到檢查型異常時(shí)不會(huì)回滾(這一行為與EJB的回滾行為是一致的)。 但是你可以聲明事務(wù)在遇到特定的檢查型異常時(shí)像遇到運(yùn)行期異常那樣回滾。同樣,你還可以聲明事務(wù)遇到特定的異常不回滾,即使這些異常是運(yùn)行期異常。

TransactionStatus接口介紹

TransactionStatus接口用來記錄事務(wù)的狀態(tài) 該接口定義了一組方法,用來獲取或判斷事務(wù)的相應(yīng)狀態(tài)信息.

PlatformTransactionManager.getTransaction(…) 方法返回一個(gè) TransactionStatus 對(duì)象。返回的TransactionStatus 對(duì)象可能代表一個(gè)新的或已經(jīng)存在的事務(wù)(如果在當(dāng)前調(diào)用堆棧有一個(gè)符合條件的事務(wù))。

TransactionStatus接口接口內(nèi)容如下:

public interface TransactionStatus{
 boolean isNewTransaction(); // 是否是新的事物
 boolean hasSavepoint(); // 是否有恢復(fù)點(diǎn)
 void setRollbackOnly(); // 設(shè)置為只回滾
 boolean isRollbackOnly(); // 是否為只回滾
 boolean isCompleted; // 是否已完成
}

到此,相信大家對(duì)“Spring事務(wù)管理的詳細(xì)介紹”有了更深的了解,不妨來實(shí)際操作一番吧!這里是億速云網(wǎng)站,更多相關(guān)內(nèi)容可以進(jìn)入相關(guān)頻道進(jìn)行查詢,關(guān)注我們,繼續(xù)學(xué)習(xí)!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI