探索邏輯事務 TransactionScope


一、什么是TransactionScope?

  TransactionScope即范圍事務(類似數據庫中的事務),保證事務聲明范圍內的一切數據修改操作狀態一致性,要么全部成功,要么全部失敗回滾.

  MSDN:如果在事務范圍內未不發生任何異常 (即之間的初始化 TransactionScope 對象並調用其 Dispose 方法),則范圍所參與的事務可以繼續,否則參與到其中的事務將回滾。
      當應用程序完成所有工作時它想要在事務中執行,應調用 Complete 方法一次,以通知該事務管理器是可接受(此時事務並未提交),即可提交事務,未能調用此方法中止事務。
      調用 Dispose 方法將標記事務范圍的末尾。 在調用此方法之后所發生的異常不會影響事務。

二、TransactionScope有什么用?

  假如現在有一個需求:實現一個下單功能,主要業務包含扣減商品庫存、扣減用戶賬戶余額、生成訂單記錄以及記錄日志。為了保證數據一致性我們通常的做法就是在數據庫建一個下訂單的事務,然后程序調用事務傳入相應的參數即可。那么問題來了,如果用戶的賬戶數據跟訂單數據分別處於不同的數據庫,就沒法在同一個數據庫事務里完成所有任務,也就沒法保證數據的一致性。
  最近由於業務的變更公司改用MySQL數據庫,處理數據變更時習慣性先寫事務,寫的時候發現現有數據庫中一個事務都沒有,於是去問java組,不使用事務怎么保證數據的一致性?得到的答復是:事務是什么鬼,spring幫我們解決所有問題...。立馬就懵逼了,.net中沒聽說有Spring啊(據說有類似的框架),雖然可以考慮使用倉儲加工作單元來解決,但是感覺好麻煩的樣子,后來尋找解決方案時發現了TransactionScope。

三、TransactionScope怎么使用?

 1 try
 2 {
 3     using (TransactionScope scope = new TransactionScope())
 4     {
 5         //TODO:數據處理業務       
 6         scope.Complete();
 7     }
 8 }
 9 catch (Exception ex)
10 {
11     throw ex;
12 }

四、問題探討

1、准備工作

 1 //數據庫訪問對象
 2 public class Studuent
 3 {
 4     public static IList<StudentModel> GetList()
 5     {
 6         //不允許臟讀
 7         string sql = "SELECT Id,Name,CreateTime FROM Student ORDER BY Id DESC;";
 8         DataTable dt = SQLHelper.ExecuteDataTable(CommandType.Text, sql);
 9         return dt.ToModel<StudentModel>();
10     }
11 
12     public static bool Add(string name)
13     {
14         SqlParameter[] parms = { new SqlParameter("@Name", SqlDbType.NVarChar, 32) { Value = name } };
15         string sql = "INSERT INTO Student (Name) VALUES (@Name)";
16         return SQLHelper.ExecuteNonQuery(CommandType.Text, sql, parms) > 0;
17     }
18 
19     public static void Clear()
20     {
21         SQLHelper.ExecuteNonQuery("DELETE Student");
22     }
23 }
 1 //公共方法,輸出學生列表
 2 static void PrintStudent()
 3 {
 4     IList<StudentModel> list = Studuent.GetList();
 5     foreach (var item in list)
 6     {
 7         Console.WriteLine("{0}\t{1}\t{2}", Thread.CurrentThread.ManagedThreadId, item.Name, item.CreateTime);
 8     }
 9     Console.WriteLine();
10 }

2、事務什么時候提交?

最初我以為在執行Complete后即刻提交,但根據輸出結果可以看出,Complete方法執行兩秒之后事務依舊沒有提交。因為不允許臟讀的原因,主線程會在事務對Student表操作完成后才可查詢完成,但學生列表是在scope調用dispose方法之后輸出,MSDN介紹說dispose確定事務范圍末尾,因此猜測事務是在調用dispose時被提交。

3、異常是怎么導致數據不被提交?

對比兩幅圖可以看出,異常在Complete之后發生並不會影響事務的提交,事務未提交是因為發生異常導致Complete未被執行。之前看過一篇文章說,如果TransactionScope范圍中沒有調用Complete會導致程序異常,我想他肯定是開玩笑的...

4、嵌套事務

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM