前面說到用數據庫中的鎖機制對并發事務進行控制,這節來說說事務方法和事務方法發生嵌套調用時事務如何進行傳播。例如:方法可能繼續在現有事務中運行,也可能開啟一個新事務,并在自己的事務中運行。例如:方法可能繼續在現有事務中運行,也可能開啟一個新事務,并在自己的事務中運行。Spring定義了七種傳播行為:
傳播行為 | 含義 |
PROPAGATION_REQUIRED | 表示當前方法必須運行在事務中。如果當前事務存在,方法將會在該事務中運行。否則,會啟動一個新的事務 |
PROPAGATION_SUPPORTS | 表示當前方法不需要事務上下文,但是如果存在當前事務的話,那么該方法會在這個事務中運行 |
PROPAGATION_MANDATORY | 表示該方法必須在事務中運行,如果當前事務不存在,則會拋出一個異常 |
PROPAGATION_REQUIRED_NEW | 表示當前方法必須運行在它自己的事務中。一個新的事務將被啟動。如果存在當前事務,在該方法執行期間,當前事務會被掛起。 |
PROPAGATION_NOT_SUPPORTED | 表示該方法不應該運行在事務中。如果存在當前事務,在該方法運行期間,當前事務將被掛起。 |
PROPAGATION_NEVER | 表示當前方法不應該運行在事務上下文中。如果當前正有一個事務在運行,則會拋出異常 |
PROPAGATION_NESTED | 表示如果當前已經存在一個事務,那么該方法將會在嵌套事務中運行。嵌套的事務可以獨立于當前事務進行單獨地提交或回滾。如果當前事務不存在,那么其行為與PROPAGATION_REQUIRED一樣。 |
一個事務中會有多個dao層接口需要與數據庫建立連接存取數據,那就需要保證這些dao操作調用的都是一個connection對象,這樣才能保證事務執行的正確性。那這又是如何保證的呢?
源碼比較多,等有時間再慢慢分析!簡單說就是:
(1)TransactionSynchronizationManager內部用ThreadLocal對象存儲資源,ThreadLocal存儲的為DataSource生成的actualKey為key值和ConnectionHolder作為value值封裝成的Map。
(2) 結合DataSourceUtils的doGetConnection函數和TransactionSynchronizationManager的bindResource函數可知:在某個線程第一次調用時候,封裝Map資源為:key值為DataSource生成actualKey【Object actualKey = TransactionSynchronizationUtils.unwrapResourceIfNecessary(key);】value值為DataSource獲得的Connection對象封裝后的ConnectionHolder。等這個線程下一次再次訪問中就能保證使用的是第一次創建的ConnectionHolder中的Connection對象。
說了事務的傳播屬性、隔離規則,順著這條線說說Spring的事務管理,先看下Spring事務管理的接口框架。
Spring并不直接管理事務,而是提供了多種事務管理器,他們將事務管理的職責委托給hibernate或者JTA等持久化機制所提供的相關平臺框架的事務來實現。
前面介紹了事務隔離規則、傳播特性,那么事務中還有那些特性?
事務超時
為了使應用程序很好地運行,事務不能運行太長的時間。因為事務可能涉及對后端數據庫的鎖定,所以長時間的事務會不必要的占用數據庫資源。事務超時就是事務的一個定時器,在特定時間內事務如果沒有執行完畢,那么就會自動回滾,而不是一直等待其結束。
回滾規則
事務五邊形的最后一個方面是一組規則,這些規則定義了哪些異常會導致事務回滾而哪些不會。默認情況下,事務只有遇到運行期異常時才會回滾,而在遇到檢查型異常時不會回滾。但是你可以聲明事務在遇到特定的檢查型異常時像遇到運行期異常那樣回滾。同樣,你還可以聲明事務遇到特定的異常不回滾,即使這些異常是運行期異常。
只讀
事務的第三個特性是它是否為只讀事務。如果事務只對后端的數據庫進行該操作,數據庫可以利用事務的只讀特性來進行一些特定的優化。通過將事務設置為只讀,你就可以給數據庫一個機會,讓它應用它認為合適的優化措施。
編程式和聲明式事務
Spring提供了對編程式事務和聲明式事務的支持,編程式事務允許用戶在代碼中精確定義事務的邊界,而聲明式事務(基于AOP)有助于用戶將操作與事務規則進行解耦。
簡單地說,編程式事務侵入到了業務代碼里面,但是提供了更加詳細的事務管理;而聲明式事務由于基于AOP,所以既能起到事務管理的作用,又可以不影響業務代碼的具體實現。
以上有的并沒有實際的開發經歷,所以感受不是很深,先作為一個了解吧!