程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> C# >> C#入門知識 >> 對TransactionScope的Complete方法的誤用

對TransactionScope的Complete方法的誤用

編輯:C#入門知識

由於找不到更好的方法,項目也沒采用任何的第三方框架(如NHibernate),所以在業務層的事務處理部分我一直用TransactionScope這個東東來管理業務事務,微軟把它翻譯為范圍事務,用它可以實現范圍內的隱式事務,具體的使用方法本文就不多講了,可以參看MSDN:http://msdn.microsoft.com/zh-cn/library/ms172152.aspx

今天我遇到一個問題,在方法A中引入TransactionScope,A中調用方法B,B中也引入了TransactionScope(TransactionScope是可以嵌套的哦),我的代碼好多都是這麼寫的:

Code
 1public OperationResult A()
 2{
 3    OperationResult result = new OperationResult();
 4    int errorCount = 0;
 5
 6    using (TransactionScope tx = new TransactionScope())
 7    {
 8        try
 9        {
10            //TODO
11        }
12        catch
13        {
14            errorCount++;
15        }
16        if (B().Result != ResultInfo.操作成功)
17        {
18            errorCount++;
19        }
20        if (C().Result != ResultInfo.操作成功) //如果B此時失敗了,調用C中的TransactionScope會出現“事務已終止”異常
21        {
22            errorCount++;
23        }
24        if (errorCount == 0)
25        {
26            result.Result = ResultInfo.操作成功;
27            tx.Complete();//我把complete全寫在了這裡
28        }
29    }
30
31    return result;
32}
33
34public OperationResult B()
35{
36    OperationResult result = new OperationResult();
37   
38    using (TransactionScope tx = new TransactionScope())
39    {
40        try
41        {
42            //TODO
43            tx.Complete();
44        }
45        catch
46        {
47            result.Result = ResultInfo.操作失敗; //現在假設catch了,此時B中的TransactionScope並沒有調用complete
48        }
49    }
50}
51
52public OperationResult C()
53{
54    OperationResult result = new OperationResult();
55   
56    //當B方法失敗時,也就是B沒執行complete時,調用到這裡會出現異常“事務已終止”
57    using (TransactionScope tx = new TransactionScope())
58    {
59        //
60    }
61}
這樣如果B中有方法執行不正確,就沒有執行complete,這樣,在被調用函數內部,直接終止了該環境事務,如果下面的代碼中還有引用TransactionScope的,就會拋出“事務已終止”的異常。


我一直以為complete應該放在“正確的業務邏輯”裡面,如果程序執行不正確就不要執行complete,它會自動回滾。我現在知道我的想法是灰常錯誤的,它是會回滾,它直接終止了都。以下是MSDN的解釋:

 

當您對范圍中的所有操作都已成功完成感到滿意時,應該僅調用此方法一次,以通知事務管理器所有資源上的狀態都是一致的,並且可以提交該事務。將該調用作為 using 塊中的最後一個語句是很好的做法。

有關如何使用此方法的更多信息,請參見 使用事務范圍實現隱式事務 主題。

未能調用此方法將中止事務,因為事務管理器將此解釋為系統故障或在事務范圍中引發了異常。但是還應該注意,調用此方法並不保證事務的提交。它只是一種將狀態通知給事務管理器的方式。在調用此方法之後,就不能再通過 Current 屬性訪問環境事務,嘗試這樣做將導致引發異常。

如果 TransactionScope 對象創建事務,則資源管理器之間的實際提交工作發生在 End Using 語句處。如果它未創建事務,則在每當 CommittableTransaction 對象的所有者調用 Commit 時發生提交。屆時事務管理器將調用資源管理器,並根據是否在 TransactionScope 對象上調用了此方法來通知它們進行提交或回滾。

 看這句“未能調用此方法將中止事務”,這也就是說,如果你不調用complete方法,事務直接終止,“因為事務管理器將此解釋為系統故障或在事務范圍中引發了異常”,所以現在我理解透徹了TransactionScope,它能保證你在它的生命周期內的隱式事務,無論你做什麼數據庫操作,它都會為你把這些操作全組織到一個環境事務中,如果你哪個環節出現問題,整個事務會隱式的回滾,complete不是告訴事務管理器馬上開始提交,而只是通知事務管理器我的操作狀態完成了,我以前把它當dbtransaction了,執行成功才submit,不成功rollback,而complete只是說“我的活干完了,你可以提交了”,如果你不在它的生命周期內調用這個方法,事務會中止,此時就像我上面寫的方法B,當你再次嘗試(using一個new TransactionScope)的時候,你會碰到“事務已終止”的錯誤。所以,我以後的代碼修改成這樣:

Code
 1public OperationResult A()
 2{
 3    OperationResult result = new OperationResult();
 4    //int errorCount = 0;這個標識變量可以扔了
 5
 6    using (TransactionScope tx = new TransactionScope())
 7    {
 8        try
 9        {
10            //TODO
11        }
12        catch
13        {
14            return result;
15        }
16        if (B().Result != ResultInfo.操作成功)
17        {
18            return result;
19        }
20        if (C().Result != ResultInfo.操作成功) //如果B此時失敗了,調用C中的TransactionScope會出現“事務已終止”異常
21        {
22            return result;
23        }
24        result.Result = ResultInfo.操作成功;
25        tx.Complete();//現在全放在TransactionScope的生命周期末尾
26    }
27
28    return result;
29}
30
31public OperationResult B()
32{
33    OperationResult result = new OperationResult();

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved