org.springframework.transaction.PlatformTransactionManager是Spring事務抽象架構的核心接口,它的主要作用是爲應用程序提供事務界定的統一方式。既然事務界定的需要很簡單,那麼PlatformTransactionManager的定義看起來也不會過於複雜.
PlatformTransactionManager是整個事務抽象策略的頂層接口,它就好像我們的戰略藍圖,而戰略的具體實施則將由相應的PlatformTransactionManager實現類來執行
Spring的事務框架針對不同的數據訪問方式以及全局事務場景,提供了相應的Platform- TransactionManager實現類。在每個實現類的職責完成之後,Spring事務框架的"統一大業"就完成了。在深入瞭解各個PlatformTransactionManager實現類的奧祕之前,不妨先考慮一下,如果讓我們來實現一個PlatformTransactionManager,要如何去做?
我們通常都是將事務管理放在Service層,而將數據訪問邏輯放在DAO層。這樣做的目的是,可以不用因爲將事務管理代碼放在DAO層,而降低數據訪問邏輯的重用性,也可以在Service層根據相應邏輯,來決定提交或者回滾事務。一般的Service對象可能需要在同一個業務方法中調用多個數據訪問對象的方法
對於我們要實現的針對JDBC的PlatformTransactionManager,只需要在事務開始的時候,通過我們的TransactionResourceManager將java.sql.Connection綁定到線程,然後在事務結束的時候解除綁定即可
Spring的事務抽象包括3個主要接口,即PlatformTransactionManager、TransactionDefinition以及TransactionStatus,
這3個接口以org.springframe- work.transaction.PlatformTran- sactionManager爲中心,互爲犄角,多少有點兒"晉西北鐵三角"的味道。
org.springframework.transac- tion.PlatformTransactionManager負責界定事務邊界。
org.spring- framework.transaction.TransactionDefinition負責定義事務相關屬性,包括隔離級別、傳播行爲等。org.springframework.transaction.PlatformTransactionManager將參照org.springframe- work.transaction.TransactionDefinition的屬性定義來開啓相關事務。
事務開啓之後到事務結束期間的事務狀態由org.springframework.transaction.TransactionStatus負責,
我們也可以通過org.springframework.transaction.TransactionStatus對事務進行有限的控制
1. TransactionDefinition簡介
org.springframework.transaction.TransactionDefinition主要定義了有哪些事務屬性可以指定,這包括:
事務的隔離(Isolation)級別
事務的傳播行爲(Propagation Behavior)
事務的超時時間(Timeout)
是否爲只讀(ReadOnly)事務
TransactionDefinition內定義瞭如下5個常量用於標誌可供選擇的隔離級別。
ISOLATION_DEFAULT。如果指定隔離級別爲ISOLATION_DEFAULT,則表示使用數據庫默認的隔離級別,通常情況下是Read Committed。
ISOLATION_READ_UNCOMMITTED。對應Read Uncommitted隔離級別,無法避免髒讀,不可重複讀和幻讀。
ISOLATION_READ_COMMITTED。對應Read Committed隔離級別,可以避免髒讀,但無法避免不可重複讀和幻讀。
ISOLATION_REPEATABLE_READ。對應Repeatable read隔離級別,可以避免髒讀和不可重複讀,但不能避免幻讀。
ISOLATION_SERIALIZABLE。對應Serializable隔離級別,可以避免所有的髒讀,不可重複讀以及幻讀,但併發性效率最低。
針對事務的傳播行爲,TransactionDefinition提供了以下幾種選擇,除了PROPAGATION_ NESTED是Spring特有的外,其他傳播行爲的語義與CMT基本相同。
PROPAGATION_REQUIRED。如果當前存在一個事務,則加入當前事務。如果不存在任何事務,則創建一個新的事務。總之,要至少保證在一個事務中運行。
PROPAGATION_REQUIRED通常作爲默認的事務傳播行爲。
PROPAGATION_SUPPORTS。如果當前存在一個事務,則加入當前事務。如果當前不存在事務,則直接執行。對於一些查詢方法來說,PROPAGATION_SUPPORTS通常是比較合適的傳播行爲選擇。如果當前方法直接執行,那麼不需要事務的支持。如果當前方法被其他方法調用,而其他方法啓動了一個事務,使用PROPAGATION_SUPPORTS可以保證當前方法能夠加入當前事務,並洞察當前事務對數據資源所做的更新。比如,A.service()會首先更新數據庫,然後調用B.service()進行查詢,那麼,如果B.service()是
PROPAGATION_SUPPORTS的傳播行爲,就可以讀取A.service()之前所做的最新更新結果(如圖19-6所示)。而如果使用稍後所提到的
PROPAGATION_NOT_SUPPORTED,則B.service()將無法讀取最新的更新結果,因爲A.service()的事務在這時還沒有提交(除非隔離級別是Read Uncommitted)。
PROPAGATION_MANDATORY。PROPAGATION_MANDATORY強制要求當前存在一個事務,如果不存在,則拋出異常。如果某個方法需要事務支持,但自身又不管理事務提交或者回滾,那麼比較適合使用PROPAGATION_MANDATORY。可以參照Java Transaction Design Strategies一書中對REQUIRED和MANDATORY兩種傳播行爲的比較,來更深入地瞭解PROPAGATION_ MANDATORY可能的應用場景。
PROPAGATION_REQUIRES_NEW。不管當前是否存在事務,都會創建新的事務。如果當前存在事務,會將當前的事務掛起(Suspend)。如果某個業務對象所做的事情不想影響到外層事務,PROPAGATION_REQUIRES_NEW應該是合適的選擇。比如,假設當前的業務方法需要向數據庫中更新某些日誌信息,但即使這些日誌信息更新失敗,我們也不想因爲該業務方法的事務回滾,而影響到外層事務的成功提交。因爲這種情況下,當前業務方法的事務成功與否對外層事務來說是無關緊要的。
PROPAGATION_NOT_SUPPORTED。不支持當前事務,而是在沒有事務的情況下執行。如果當前存在事務的話,當前事務原則上將被掛起(Suspend),但這要看對應的PlatformTransaction- Manager實現類是否支持事務的掛起。更多情況請參照TransactionDefinition的Javadoc文檔。PROPAGATION_NOT_SUPPORTED與
PROPAGATION_SUPPORTS之間的區別,可以參照PROPAGATION_ SUPPORTS部分的實例內容。
PROPAGATION_NEVER。永遠不需要當前存在事務,如果存在當前事務,則拋出異常。
PROPAGATION_NESTED。如果存在當前事務,則在當前事務的一個嵌套事務中執行,否則與PRO- PAGATION_REQUIRED的行爲類似,即創建新的事務,在新創建的事務中執行。PROPAGATION_ NESTED粗看起來好像與PROPAGATION_REQUIRES_NEW的行爲類似,實際上二者是有差別的。PROPAGATION_REQUIRES_NEW創建的新事務與外層事務屬於同一個"檔次",即二者的地位是相同的。當新創建的事務運行的時候,外層事務將被暫時掛起。而PROPAGATION_NESTED創建的嵌套事務則不然,它是寄生於當前外層事務的,它的地位比當前外層事務的地位要小一號。當內部嵌套事務運行的時候,外層事務也是處於active狀態,圖19-7演示了PROPAGATION_
REQUIRES_NEW和PROPAGATION_NESTED中涉及的多個事務相互之間的地位。