Spring事務原理


Spring事務的本質是對數據庫事務的封裝支持,沒有數據庫對事務的支持,Spring本身無法提供事務管理功能。對於用JDBC操作數據庫想要用到事務,必須經過獲取連接——》開啟事務——》執行CRUD操作——》提交/回滾事務——》關閉連接幾部分操作。使用Spring管理事務后,可以省掉自己寫代碼開啟、提交/回滾事務的操作。

Spring事務通過AOP動態代理實現,使用上通常要先在配置文件中開啟事務,然后通過xml文件或注解配置要執行注解的類方法,然后在調用對應類實例方法時,Spring會自動生成代理,在調用前設置事務操作、調用方法后進行事務回滾或提交操作。

Spring事務的SPI(服務提供接口,給第三方服務實現類提供的接口實現要求)接口主要有:TransactionDefinition、PlatformTransactionManager、TransactionStatus。

1、org.springframework.transaction.TransactionDefinition,它用於定義一個事務。它包含了事務的靜態屬性,比如:事務傳播行為、隔離級別、超時時間等等。

wKioL1iYRi2jSv47AAA-pQfu-Kc846.png

Spring 為我們提供了一個默認的實現類:DefaultTransactionDefinition,該類適用於大多數情況。如果該類不能滿足需求,可以通過實現 TransactionDefinition 接口來實現自己的事務定義。

wKiom1iYRi_DlNurAADCweOsT9c214.png

2、org.springframework.transaction.PlatformTransactionManager,用於執行具體的事務操作,方法列表如下:全部拋出TransactionException異常

wKiom1iYRizAPu_iAAAY25Tdllg370.png

PlatformTransactionManager 的主要實現類大致如下:

wKioL1iYRjGiHEl-AACPwH4KMAk869.png

 

根據底層所使用的不同的持久化 API 或框架,使用如下:

 DataSourceTransactionManager:適用於使用JDBC和iBatis進行數據持久化操作的情況。

 HibernateTransactionManager:適用於使用Hibernate進行數據持久化操作的情況。

 JpaTransactionManager:適用於使用JPA進行數據持久化操作的情況。

 另外還有JtaTransactionManager 、JdoTransactionManager、JmsTransactionManager等等。

如果我們使用JTA進行事務管理,我們可以通過 JNDI 和 Spring 的 JtaTransactionManager 來獲取一個容器管理的 DataSource。JtaTransactionManager 不需要知道 DataSource 和其他特定的資源,因為它將使用容器提供的全局事務管理。而對於其他事務管理器,比如DataSourceTransactionManager,在定義時需要提供底層的數據源作為其屬性,也就是 DataSource。與 HibernateTransactionManager 對應的是 SessionFactory,與 JpaTransactionManager 對應的是 EntityManagerFactory 等等。

下面分析DataSourceTransactionManager,指明dataSourcce:javax.sql.DataSource。

wKiom1iYRiyhp2ZxAABWuxSXXks378.png

注入dataSourcce:

<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">

         <property name="dataSource" ref="dataSource" />

</bean>  

3、TransactionStatus

PlatformTransactionManager.getTransaction(…) 方法返回一個 TransactionStatus 對象。返回的TransactionStatus 對象可能代表一個新的或已經存在的事務(如果在當前調用堆棧有一個符合條件的事務)。TransactionStatus 接口提供了一個簡單的控制事務執行和查詢事務狀態的方法。

 

TransactionStatus 接口中定義的主要方法

public  interface TransactionStatus{

   boolean isNewTransaction();

   void setRollbackOnly();

   boolean isRollbackOnly();

}

事務的隔離級別

默認是數據庫事務的隔離級別,大部分數據庫是讀提交(可解決臟讀問題,事務未提交前被數據被其它事務讀到),MySQL 是可重復讀(一個事務中間進行了兩次數據讀操作,因為兩次之間有其它事務對數據進行了update,而導致兩次讀取的數據不一致),最高的隔離級別是串讀(可解決幻讀問題,一個事務讀了兩次某一范圍的數據,中間其它事務對這一范圍數據做了增加或刪除操作而導致前后讀到的數據條數不一致。與不可重復讀的區別時前者是范圍內數據受到增加或刪除影響,需要鎖表解決,后者是受到數據修改的影響,可以通過鎖行解決)

事務的傳播特性

常用的傳播特性有PROPAGATION_REQUIRED、PROPAGATION_REQUIRES_NEW、PROPAGATION_NESTED三種,要注意它們之間的區別。

使用嵌套事務的場景有兩點需求:

  1. 需要事務BC與事務AD一起commit,即:作為事務AD的子事務,事務BC只有在事務AD成功commit時(階段3成功)才commit。這個需求簡單稱之為“聯合成功”。這一點PROPAGATION_REQUIRED可以做到。
  2. 需要事務BC的rollback不(無條件的)影響事務AD的commit。這個需求簡單稱之為“隔離失敗”。這一點PROPAGATION_REQUIRES_NEW可以做到。

使用PROPAGATION_REQUIRED滿足需求1,但子事務BC的rollback會無條件地使父事務AD也rollback,不能滿足需求2。

使用PROPAGATION_REQUIRES_NEW滿足需求2,但子事務(這時不應該稱之為子事務)BC是完全新的事務上下文,父事務(這時也不應該稱之為父事務)AD的成功與否完全不影響BC的提交,不能滿足需求1。

同時滿足上述兩條需求就要用到PROPAGATION_NESTED了。PROPAGATION_NESTED在事務AD執行到B點時,設置了savePoint(關鍵)。

當BC事務成功commit時,PROPAGATION_NESTED的行為與PROPAGATION_REQUIRED一樣。只有當事務AD在D點成功commit時,事務BC才真正commit,如果階段3執行異常,導致事務AD rollback,事務BC也將一起rollback ,從而滿足了“聯合成功”。

 當階段2執行異常,導致BC事務rollback時,因為設置了savePoint,AD事務可以選擇與BC一起rollback或繼續階段3的執行並保留階段1的執行結果,從而滿足了“隔離失敗”。

PROPAGATION_REQUIRED


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM