


版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領
文檔簡介
1、談談分布式事務之三System.Transactions 事務詳解 下篇 在前面一篇給出的 Transaction 的定義中, 信息的讀者應該看到了一個叫做 DepedentClone 的方法。該方法對用于創建基于現有 Transaction 對象的“依賴事務( DependentTransaction)”。不像可提交事務是一個獨立的事務對象,依賴事務依附于現有的某個事務(可能是可提交事務,也可能是依賴事務) 。依賴事務可以幫助我們很容易地編寫一些事務型操作,當環境事務不存的時候,可以確保操作在一個獨立的事務中執行;當環境事務存在的時候,則自動加入其中。 一、依賴事務( Dependent T
2、ransaction) 依賴事務通過 DependentTransaction 類型表示, DependentTransaction 定義如下。和 CommittableTransaction一樣, DependentTransaction 也是 Transaction 的子類。既然 DependentTransaction 依賴于現有的 Transaction 對象而存在,相當于被依賴事務的子事務,所以無法執行對事務的提交,也自然不會定義Commit 方法。但是, DependentTransaction具有一個唯一的方法成員:Complete 。調用這個方法意味著向被依賴事務發送通知,表明
3、所有與依賴事務相關的操作已經完成。1: Serializable2: public sealed classDependentTransaction : Transaction3: 4:publicvoid Complete();5: 1、通過 DependentTransaction 將異步操所納入現有事務通過 Transaction 的靜態屬性Current 表示的環境事務保存在TLS( Thread Local Storage)中,所以環境事務是基于當前線程的。這就意味著,即使環境事務存在,通過異步調用的操作也不可能自動加入到當前事務之中,因為在異步線程中感知不到環境事務的存在。在這種情
4、況下,我們需要做的就是手工將當前事務傳遞到另一個線程中,作為它的環境事務。通過依賴事務我們很容易實現這一點。DependentTransaction 通過 Transaction 的 DependentClone 方法創建,該方法具有一個DependentCloneOption 枚舉類型的參數,體現了被依賴的事務再上尚未接受到依賴事務的通知(調用 Complete 或者 Rollback 方法)得情況下,提交或者完成所采取的事務控制行為。DependentCloneOption 提供了兩個選項, BlockCommitUntilComplete表示被依賴事務會一直等待接收到依賴事務的通知或者超
5、過事務設定的超時時限;而 RollbackIfNotComplete 則會直接將被依賴的事務回滾,并拋出 TransactionAbortedException 異常。 1: Serializable2: public class Transaction : IDisposable, ISerializable 3: 4: /其他成員 5: public DependentTransaction DependentClone(DependentCloneOption cloneOption); 6: 7: public enum DependentCloneOption 8: 9: Block
6、CommitUntilComplete, 10:RollbackIfNotComplete11: 下面的代碼演示了如果通過依賴事務,采用異步的方式進行銀行轉賬操作。借助于組件ThreadPool,將主線程環境事務的依賴事務傳遞給異步操作代理,開始異步操作的時候將此依賴事務作為當前的環境事務,那么之后的操作將自動在當前事務下進行。1: private static void Transfer(stringaccountFrom, string accountTo, double amount)2: 3:Transaction originalTransaction = Transaction.C
7、urrent;4:CommittableTransaction transaction = newCommittableTransaction();5:try6:7:Transaction.Current = transaction;8:ThreadPool.QueueUserWorkItem(state =>9:10:Transaction.Current = state asDependentTransaction; 11:try12:13:Withdraw(accountFrom, amount);14:Deposite(accountTo, amount);15:(sta
8、te as DependentTransaction).Complete();16:17:catch (Exception ex)18:19:Transaction.Current.Rollback(ex);20: 21:finally22: 23:(state asIDisposable).Dispose();24:Transaction.Current = null;25:26:,lockCommitUntilComplete);27:/其他操作28:transaction.Commit();29:30:catch(TransactionAbortedException ex)31:32:
9、transaction.Rollback(ex);33:Console.WriteLine("轉帳失敗,錯誤信息:0", ex.InnerException.Message);34: 35:catch (Exception ex) 36:37:transaction.Rollback(ex);38:throw;39:40:finally41:42:Transaction.Current = originalTransaction;43:transaction.Dispose();44:45: 由于在調用 DependentClone 方法創建依賴事務時指定的參數為 Depe
10、ndentCloneOption.BlockCommitUntilComplete,所以主線程在調用Commit 方法提交事務的時候,由于依賴事務尚未結束(調用Complete 或者 Rollback 方法),在這里會一直等待。如果依賴事務的Complete 或者 Rollback 一直沒有調用,那么被依賴的事務會一直等到超出事務設置的超時時限。所以,對于基于BlockCommitUntilComplete選項創建的依賴事務來說,應該及時地調用Complete或者Rollback方法。2、通過 DependentTransaction 實現事務型方法這里所說的事務型方法是指方法的執行總是在事務
11、中執行。具體來講,有兩種不同的事務應用場景:如果當前不存在環境事務,那么方法的執行將在一個獨立的事務中執行; 反之,如果存在環境事務,在方法執行會自動加入到環境事務之中。比如說,存儲( Deposit )和提取( Withdraw )就是典型的事務型操作。對于單純的存取款的場景,應該創建一個新的事務來控制存儲和提取操作的執行,以確保單一帳戶款項的數據一致性。如果在轉賬的場景中,應在在轉賬開始之前就創建一個新的事務,讓提取和存儲的操作自動加入到這個事務之中。我們現在就結合可提交事務和依賴事務將 Deposit 和 Withdraw 兩個方法定義成事務型方法,為了相同代碼的重復,在這里把事務控制部
12、分定義在如下一個InvokeInTransaction 靜態方法中 :1: static voidInvokeInTransaction(Action action)2: 3:Transaction originalTransaction = Transaction.Current;4:CommittableTransaction committableTransaction = null;5:DependentTransaction dependentTransaction = null;6:if (null = Transaction.Current)7:8:committableTran
13、saction = new CommittableTransaction();9:Transaction.Current = committableTransaction;10:11:else12:13:dependentTransaction =Transaction.Current.DependentClone(DependentCloneOption.RollbackIfNotComplete);14:Transaction.Current =dependentTransaction;15:16:17:try18:19:action();20:if (null !=committable
14、Transaction) 21:22:committableTransaction.Commit();23:24:25:if (null != dependentTransaction)26:27:dependentTransaction.Complete();28:29:30:catch (Exception ex)31:32:Transaction.Current.Rollback(ex);33:throw;34:35:finally36: 37:Transaction transaction = Transaction.Current;38:Transaction.Current = o
15、riginalTransaction;39:transaction.Dispose(); 40: 41: InvokeInTransaction 方法的參數是一個 Action 類型的代理( Delegate),表示具體的業務操作。在開始的時候記錄下當前的環境事務,當整個操作結束之后應該環境事務恢復成該值。如果存在環境事務,則創建環境事務的依賴事務,反之直接創建可提交事務。并將新創建的依賴事務或者可提交事務作為當前的環境事務。將目標操作的執行(action)放在try/catch 中,當目標操作順利執行后,調用依賴事務的Complete 方法或者可提交事務的Commit 方法。如果拋出異常,則
16、調用環境事務的Rollback 進行回滾。 在 finally 塊中將環境事務恢復到之前的狀態,并調用Dispose 方法對創建的事務進行回收。借助于 InvokeInTransaction 這個輔助方法,我們以事務型方法的形式定義了如下的兩個方法:Withdraw 和 Deposit,分別實現提取和存儲的操作。1: static void Withdraw(stringaccountId, double amount)2: 3:Dictionary<string, object> parameters = newDictionary<string,
17、object>();4:parameters.Add("id", accountId);5:parameters.Add("amount", amount);6:InvokeInTransaction() => DbAccessUtil.ExecuteNonQuery("P_WITHDRAW",parameters);7: 8:9: static voidDeposit(string accountId, double amount)10: 11:Dictionary<string, obje
18、ct> parameters = newDictionary<string, object>();12:parameters.Add("id", accountId);13:parameters.Add("amount", amount);14:InvokeInTransaction() =>DbAccessUtil.ExecuteNonQuery("P_DEPOSIT", parameters);15: 二、 TransactionScope在上面一節,我結合可提交事務和依賴事
19、務,以及環境事務的機制提供了對事務型操作的實現。實際上,如果借助TransactionScope,相應的代碼將會變得非常簡單。下面的代碼中,通過TransactionScope對InvokeInTransaction進行了改寫,從執行效果來看這和原來的代碼完全一致。1: staticvoid InvokeInTransaction(Action action)2: 3:using (TransactionScope transactionScope = newTransactionScope()4:5:action();6:transactionScope.Complete();7:8: 通過
20、 InvokeInTransaction 方法前后代碼的對比,我們可以明顯看到 TransactionScope 確實能夠使我們的事務控制變得非常的簡單。實際上,在利用System.Transactions 事務進行編程的時候,我們一般不會使用到可提交事務,對于依賴事務也只有在異步調用的時候會使用到,基于TransactionScope的事務編程方式才是我們推薦的。正如其名稱所表現的一樣,TransactionScope 就是為一組事務型操作創建一個執行范圍,而這個范圍始于TransactionScope創建之時,結束于TransactionScope 被回收(調用Dispose方法)。在對
21、TransactionScope 進行深入介紹之前,照例先來看看它的定義:1: public sealed class TransactionScope :IDisposable2: 3:public TransactionScope();4:public TransactionScope(Transaction transactionToUse);5:public TransactionScope(TransactionScopeOption scopeOption);6: public TransactionScope(Transaction transactionToUse, TimeS
22、pan scopeTimeout); 7: public TransactionScope(TransactionScopeOption scopeOption, TimeSpan scopeTimeout); 8: public TransactionScope(TransactionScopeOption scopeOption, TransactionOptions transactionOptions); 9: publicTransactionScope(Transaction transactionToUse, TimeSpanscopeTimeout, EnterpriseSer
23、vicesInteropOption interopOption);10: public TransactionScope(TransactionScopeOption scopeOption, TransactionOptions transactionOptions, EnterpriseServicesInteropOption interopOption); 11: 12: public void Complete(); 13: public void Dispose(); 14: 我們可以看到TransactionScope 實現了IDisposable接口,除了Dispose方法之
24、外,僅僅具有一個唯一的方法:Complete。但是 TransactionScope 卻有一組豐富的構造函數。我們先來看看這些構造函數相應的參數如何影響TransactionScope 對事務控制的行為。1、 TransactionScopeOption實際上前面一節中提供的InvokeInTransaction 方法基本上體現了 TransactionScope 的內部實現。也就是說,TransactionScope 也是通過創建可提交事務或者依賴事務,并將其作為事務范圍內的環境事務,從而將范圍的所有操作納入到一個事務之中。通過在構造函數中指定TransactionScopeOption 類
25、型的scopeOption 參數,控制TransactionScope 當環境事務存在的時候應該采取怎樣的方式執行事務范圍內的操作。具有來講,具有三種不同的方式:如果已經存在環境事務,則使用該環境事務。否則,在進入范圍之前創建新的事務;總是為該范圍創建新事務;環境事務上下文在創建范圍時被取消。范圍中的所有操作都在無環境事務上下文的情況下完成。TransactionScopeOption是一個枚舉,三個枚舉值Required、RequiresNew和Suppress 依次對應上面的三種行為。1:public enum TransactionScopeOption2: 3:Required,4:R
26、equiresNew,5:Suppress6: 對于Required選項,如果當前存在環境事務TransactionScope會創建環境事務的依賴事務,負責創建可提交事務,然后將創建的環境事務或者可提交事務作為事務范圍的環境事務。如對于 RequiresNew 選項,TransactionScope 總是會創建可提交事務并將其作為事務范圍的環境事務,意味著控制事務范圍內操作的事務也當前的環境事務已經沒有任何關系。如果Suppress選項,TransactionScope 會將事務范圍內的環境事務設為空,意味著事務范圍內的操作并不受事務的控制。Required 是默認選項,意味著事務范圍內的事務
27、將會作為當前環境事務的一部分。如果你不希望某個操作被納入當前的環境事務,但是相應的操作也需要事務的控制以確保所操作數據的一致性。比如,當業務邏輯失敗導致異常拋出,需要對相應的錯誤信息進行日志記錄。對于日記的操作就可以放入基于 RequiresNew 選項創建 TransactionScope 中。對于一些不重要的操作(操作的錯誤可被忽略),并且不需要通過事務來控制的操作,比如發送一些不太重要的通知,就可以采用 Suppress 選項。2、 TransactionOptions 和 EnterpriseServicesInteropOptionTransactionOptions 在前面已經提及
28、,用于控制事務的超時時限和隔離級別。對于超時時限,你也可以選擇TransactionScope 相應能夠的構造函數以TimeSpan 的形式指定。而對于事務的隔離級別,需要著重強調一點:當選擇TransactionScopeOption.Required 選項時, TransactionScope指定的隔離級別必須與環境事務(如果有)相匹配。比如下面的例子中,我定義兩個嵌套的TransactionScope,外部的 TransactionScope 采用默認的隔離級別,內部在采用ReadCommitted 隔離級別,當執行這段代碼的時候,會拋出如圖 1 所示的 ArgumentExceptio
29、n 異常。 1: using (TransactionScope outerScope = new TransactionScope() 2: 3: TransactionOptions transactionOptions = new TransactionOptions() IsolationLevel =IsolationLevel.ReadCommitted ;4:using(TransactionScope innerScope = newTransactionScope(TransactionScopeOption.Required,transactionOptions)5:6:/
30、事務型操作7:innerScope.Complete();8:9:/事務型操作10:outerScope.Complete();11:圖 1隔離級別不一致導致的異常實際上在 System.Transactions 事務機制被引入之前,像Enterprise Service 主要依賴于基于COM+ 的分布式事務。TransactionScope 通過 EnterpriseServicesInteropOption 控制System.Transactions 事務如何與COM+ 的分布式事務進行互操作。具有來講具有如下三種互操作選項,分別和EnterpriseServicesInteropOption 三個枚舉值相對應:None:Transaction 和 Current 之間不同步;Automatic :搜索現有的COM+上下文并與之同步(如該上下文存在);Full : System.EnterpriseServices 上下文(可通過調用ContextUtil 類的靜態方法 Transaction 來檢索)和 System.Transactions 環境事務(可通過調用 Transaction 類的靜態方法 Current 來檢索)始終保持同步。這將引入性能損失,因為可
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯系上傳者。文件的所有權益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
- 4. 未經權益所有人同意不得將文件中的內容挪作商業或盈利用途。
- 5. 人人文庫網僅提供信息存儲空間,僅對用戶上傳內容的表現方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
- 6. 下載文件中如有侵權或不適當內容,請與我們聯系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 六一毽子場館活動方案
- 六一活動吃美食活動方案
- 六一活動摔跤活動方案
- 六一活動泳裝秀活動方案
- 六一特殊展示活動方案
- 六一粽子活動方案
- 六一花束活動方案
- 六五廣場宣傳活動方案
- 六年級朗誦大賽活動方案
- 安全上崗試題及答案
- 【MOOC】電工學-西北工業大學 中國大學慕課MOOC答案
- 四川省成都市2024年七年級下學期期末數學試題附答案
- 2023版押品考試題庫必考點含答案
- 尿動力學檢查操作指南2023版
- 哈工大橋梁基礎與墩臺復習總結盛洪飛
- 框架六層中學教學樓工程施工方案
- 淺析Zabbix平臺在電力企業信息設備監控中的應用
- 螯合樹脂資料
- 電力工程監理規劃
- 案例同仁堂的新生
- 吉林省抗菌藥物臨床應用分級管理目錄(版
評論
0/150
提交評論