新世代交易管理機制~System.Transactions
Transaction交易處理在嚴謹度較高的應用程式必備的基本功能,傳統.NET處理交易有兩種途徑,一是使用ADO.NET為主的SqlTransaction,另一就是透過Enterprise Services(COM+)來達成,那新世代的交易機制還提供了另一種更優的選擇,就是System.Transaction。
--------------------------------------------------------------------------------
【本文內容及程式碼引用聖殿祭司ASP.NET 3.5新書】
在一開始撰寫【新世代交易管理機制~System.Transactions】這章時,我足足焦慮心煩了三天,因為不知道該如何下筆談這章,不是程式面的問題,而是"脈絡",如果我無法告訴讀者說System.Transaction交易管理機制創造的由來,還有使用它的目的,即使貼了一堆實作的程式碼,我個人也會認為是沒用的知識,是失敗的作品,程式不怕不會寫,因為可抄可參考的太多了,但可怕的是,無法辨證程式運用場合是否正確?是否為合理的運用?擺了一堆莫名奇妙的Code在自己的專案中,自已又說不出的所以然,我想這才是為日後問題發生時,埋下一個致命因素,好再我看了很多國外專家的文章,了解System.Transaction創造的起源,再加上我自己的研究心得,最後這星期終於完成了System.Transactions的寫作主題,以下開始是介紹。
傳統.NET1.x的交易程式機制有兩種:
(1)ADO.NET明確交易,指SqlTransaction。
(2)Enterprise Services的宣告式交易兩種。
然而本章所要談的主角不是以上兩者,而是System.Transactions新世代的交易管理機制,System.Transactions是一個命名空間,而裡面包含許多和交易有關的類別,但要說明為什麼要發明System.Transactions這個東西之前,就要先解釋傳統(1)ADO.NET明確交易(2)Enterprise Services的宣告式交易的缺點及侷限性:
(1)ADO.NET明確交易
ADO.NET明確交易效能最快,吃系統資源最少,但是功能過份簡單,只能管理單一物件和單一持久資源間的交易,也就是它只能應付單一SqlConnection對單一SQL Server之間的交易管理(或是Oracle),而無法應付多個SqlConnection對多個SQL Server間的分散式交易。
(2)Enterprise Services的宣告式交易
Enterprise Services的宣告式交易透過COM+型式來提供交易服務,並且需要用到MSDTC(Microsoft Distributed Transaction Coordinator)來協調分散式交易,交易功能最為強大,但是會付出較為昂貴的成本代價,而交易執行的速度最慢。
註:
MSDTC之所以較慢與使用成本較大有兩個主要原因:
1. 因為MSDTC與你的應用程式分處於不同的Process行程。而不同行程在溝通時就會涉及訊息的序列化與反序列化的動作,因而造成CPU及Memory等額外的成本。
2. MSDTC必須要整合交易中所有的Resource Manager,包含跨AppDomain、跨Processes、跨Machines。各會可以想像當現實世界中,若你需要協調一群人的動作或意見時,有時即便是簡單的工作,中間的過程都可能是沒有效率的,甚至等待回應時間也是很漫長的。
因此各位可以體會到傳統交易程式是一種極端的二分法選擇,明確交易優點是速度快、吃資源少,每個Programmer都想要,但缺點是功能太簡單,也是每個Programmer都想提升的;那Enterprise Services的宣告式交易功能最強,也許能力上比較沒有可挑剔的,但是速度上又快不起來。故綜合以上兩點,可想而知Programmer心中會有多麼地掙扎,為什麼.NET不給我一個執行速度既快,功能又強的交易管理機制?好比男仕選擇女友或老婆時,一位美麗但不富有,另一位富有但不美麗,不知男仕心中會不有極度掙扎!?若這時出現了第三位,既美麗又富有,我想應該男仕也沒什麼好掙扎了,當然挑第三位。
相同的狀況也發生在Transaction程式的世界,傳統的兩種方法優缺點都過份極端,為了調合這種不完美,微軟推出了System.Transactions新世代的交易管理機制(或稱程式撰寫模型),它屬於輕量級的交易管理機制,執行速度可以和SqlTransaction之類的程式媲美,另一方面可以動態決定是否需要從Local Transaction升級成分散式交易間,最後達到的效能與功能的平衡點,總算讓人覺得還有另一個不錯的選擇。
而System.Transactions交易是屬於輕量級交易管理者(Lightweight Transaction Manager),對於交易程式的撰寫模型有兩個:(1)隱含交易程式撰寫模型,使用TransactionScope類別來建立,(2)明確交易程式撰 寫模型,使用Transaction或CommitableTransation類別來建立,System.Transactions可以從Local transaction交易視需要升級為Distributed Transaction分散式交易,這是最大的目的。
例如使用TransactionScope類別所建立的隱含交易程式:
1 //宣告TransationScope隱含交易
2 using (TransactionScope ts = newTransactionScope())
3 {
4 string connString = WebConfigurationManager.ConnectionStrings["NorthwindConnectionString"].ConnectionString;
5 SqlConnection conn = newSqlConnection(connString);
6 conn.Open();
7
8 string strSQL = "INSERT INTO Employees(FirstName, LastName, City, Address) values (@paramFirstName,@paramLastName,@paramCity,@paramAddress)";
9 SqlCommand cmd = newSqlCommand(strSQL, conn);
10
11 try
12 {
13 cmd.Parameters.Add("@paramFirstName", SqlDbType.NVarChar, 20).Value = txtFirstName.Text;
14 cmd.Parameters.Add("@paramLastName", SqlDbType.NVarChar, 10).Value = txtLastName.Text;
15 cmd.Parameters.Add("@paramCity", SqlDbType.NVarChar, 15).Value = txtCity.Text;
16 cmd.Parameters.Add("@paramAddress", SqlDbType.NVarChar, 60).Value = txtAddress.Text;
17 cmd.ExecuteNonQuery();
18 txtMsg.Text = "新增資料成功,交易確認!";
19 ts.Complete();
20 }
21 catch
22 {
23 txtMsg.Text = "新增資料失敗,交易Rollback!";
24 }
25
26 finally
27 {
28 conn.Close();
29 conn.Dispose();
30 cmd.Dispose();
31 }
32 }
使用CommittableTransaction類別所建立的明確交易程式:
1 //宣告CommittableTransaction明確交易
2 using (CommittableTransaction tran = newCommittableTransaction())
3 {
4 string connString = WebConfigurationManager.ConnectionStrings["NorthwindConnectionString"].ConnectionString;
5 SqlConnection conn = newSqlConnection(connString);
6 conn.Open();
7 conn.EnlistTransaction(tran); //登記加入明確交易
8
9 string strSQL = "INSERT INTO Employees(FirstName, LastName, City, Address) values (@paramFirstName,@paramLastName,@paramCity,@paramAddress)";
10 SqlCommand cmd = newSqlCommand(strSQL, conn);
11
12 try
13 {
14 cmd.Parameters.Add("@paramFirstName", SqlDbType.NVarChar, 20).Value = txtFirstName.Text;
15 cmd.Parameters.Add("@paramLastName", SqlDbType.NVarChar, 10).Value = txtLastName.Text;
16 cmd.Parameters.Add("@paramCity", SqlDbType.NVarChar, 15).Value = txtCity.Text;
17 cmd.Parameters.Add("@paramAddress", SqlDbType.NVarChar, 60).Value = txtAddress.Text;
18 cmd.ExecuteNonQuery();
19 txtMsg.Text = "新增資料成功,交易確認!";
20 throw new Exception("想反悔了,取消Insert!!!");
21 tran.Commit(); //確認交易
22 }
23 catch
24 {
25 txtMsg.Text = "新增資料失敗,交易Rollback!";
26 tran.Rollback(); //回復交易
27 }
28
29 finally
30 {
31 conn.Close();
32 conn.Dispose();
33 cmd.Dispose();
34 }
35 }
最後,學會了TransactionScope隱含交易及CommittableTransaction明確交易程式之撰寫,不過那並不是最主要之重點,而真正的重點卻是來自於LTM的特質,LTM在面對交易管理時,若可以在Local Transaction完成的,絕不會非得使用分散式交易管理,如此可達到成本與速度兼優的好處,而當Local Transaction不能應付交易時,則它又可以具備提升到分散式交易的延展性,並且不需要Programmer涉入太多的交易管理細節。