可通過調用一個方法來嵌套事務範圍,該方法在使用其自己範圍的方法中使用 TransactionScope,下面示例中的 RootMethod 方法就是前者這樣的方法。
- void RootMethod()
- {
- using(TransactionScope scope = new TransactionScope())
- {
- SomeMethod();
- scope.Complete();
- }
- }
- void SomeMethod()
- {
- using(TransactionScope scope = new TransactionScope())
- {
- scope.Complete();
- }
- }
最頂層事務範圍稱爲根範圍。
TransactionScope 類提供了多個重載構造函數,它們接受 TransactionScopeOption 類型的枚舉,而該枚舉定義範圍的事務行爲。
TransactionScope 對象有以下三個選項:
-
聯接環境事務,或者在環境事務不存在的情況下創建新的環境事務。
-
成爲新的根範圍,也就是說,啓動一個新事務並使該事務成爲其自己範圍中的新環境事務。
-
根本不參與事務。因此沒有環境事務。
如果用 Required 實例化範圍並且存在環境事務,則該範圍會聯接該事務。相反,如果不存在環境事務,該範圍就會創建新的事務併成爲根範圍。這是默認值。在使用Required 時,無論範圍是根範圍還是僅聯接環境事務,該範圍中的代碼都不需要有不同的行爲。該代碼在這兩種情況下的行爲應相同。
如果用 RequiresNew 實例化範圍,則它始終爲根範圍。它會啓動一個新事務,並且其事務成爲該範圍中的新環境事務。
如果用 Suppress 實例化範圍,則無論是否存在環境事務,範圍都從不參與事務。用此值實例化的範圍始終使其環境事務爲 null。
下表概括了上述這些選項。
TransactionScopeOption | 是否存在環境事務 | 範圍參與 |
---|---|---|
Required |
否 |
參與新事務(將成爲根範圍) |
Requires New |
否 |
參與新事務(將成爲根範圍) |
Suppress |
否 |
不參與任何事務 |
Required |
是 |
參與環境事務 |
Requires New |
是 |
參與新事務(將成爲根範圍) |
Suppress |
是 |
不參與任何事務 |
在 TransactionScope 對象聯接現有環境事務時,除非範圍中止該事務,否則釋放範圍對象的操作可能並不會結束事務。如果環境事務是由根範圍創建的,則僅當釋放根範圍時,纔會對事務調用 Commit。如果事務是手動創建的,則它將在中止或由其創建者提交時結束。
下面的示例演示一個 TransactionScope 對象,該對象創建了三個嵌套的範圍對象,並用不同的 TransactionScopeOption 值對其中每個對象進行了實例化。
- using(TransactionScope scope1 = new TransactionScope())
- //Default is Required
- {
- using(TransactionScope scope2 = new
- TransactionScope(TransactionScopeOption.Required))
- {
- ...
- }
- using(TransactionScope scope3 = new TransactionScope(TransactionScopeOption.RequiresNew))
- {
- ...
- }
- using(TransactionScope scope4 = new
- TransactionScope(TransactionScopeOption.Suppress))
- {
- ...
- }
- }
下面的示例演示一個不包含任何環境事務的代碼塊,它使用 Required 創建了一個新範圍 (scope1)。範圍 scope1 是根範圍,因爲它創建了一個新事務(事務 A),並使事務 A 成爲環境事務。Scope1 後來又創建了三個對象,並用不同的 TransactionScopeOption 值對其中每個對象進行了實例化。例如,scope2 是用 Required 創建的;由於存在環境事務,因此該範圍聯接 scope1 所創建的第一個事務。請注意,scope3 是新事務的根範圍,而 scope4 則沒有環境事務。
雖然 TransactionScopeOption 的默認值和最常用的值是 Required,但其他各值都有其獨有的用途。
如果要保留代碼段所執行的操作,並且不希望在操作失敗的情況下中止環境事務,此時 Suppress 十分有用。例如,在要執行日誌記錄或審覈操作時,或者在無論環境事務提交還是中止都要將事件發佈給訂戶時。使用此值,可以在事務範圍中包含非事務代碼段,如下面的示例所示。
- using(TransactionScope scope1 = new TransactionScope())
- {
- try
- {
- //Start of non-transactional section
- using(TransactionScope scope2 = new
- TransactionScope(TransactionScopeOption.Suppress))
- {
- //Do non-transactional work here
- }
- //Restores ambient transaction here
- }
- catch
- {}
- //Rest of scope1
- }