uncategorized

CommittableTransaction & TransactionScope 用法

在程式撰寫中常常會遇到需要做資料Transaction的機制,當有異常時需要透過Rollback還原。在.NET中有兩種Transaction模式分別是明確交易隱含交易。通常使用的方式分別為CommittableTransaction & TransactionScope

  • TransactionScope:類別提供一個簡單的方式,讓您不用與交易互動,即可將一段程式碼標記為參與交易,此方式只需要在程序範圍內加入Complete()就可以
  • CommittableTransaction:類別為應用程式提供使用交易的明確方式,而非隱含地使用 TransactionScope 類別,這部分需要透過呼叫Commit()Rollback()方法

這兩種方式撰寫方式比早期使用SqlTransaction方式簡單多了,且可用的東西也強化了。這兩種效能是否有明顯差異還需要再測試下面程式碼的處理情境是在填入資料前,我先將所有資料表內資料刪除再進行Insert,若是有錯誤則Rollback。使用此兩個類別都需要參考System.Transactions

CommittableTransaction


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
string strSQL = "delete [dbo].[TestTB]";
using (SqlConnection SQL = new SqlConnection("data source=.;Initial Catalog=test;User ID=test;Password=1234"))
{
CommittableTransaction ct = new CommittableTransaction();
SQL.Open();
SQL.EnlistTransaction(ct);
using (SqlCommand sqlcom = new SqlCommand())
{
try
{
sqlcom.Connection = SQL;
sqlcom.CommandText = strSQL;
sqlcom.ExecuteNonQuery();
for (int i = 0; i < 1000; i++)
{
sqlcom.CommandText = string.Format("insert into [dbo].[TestTB] (A,B,C,D,E,F,H) values ('A{0}','A{1}','A{2}','A{3}','A{4}','A{5}',{6})", i, i + 1, i + 2, i + 3, i + 4, i + 9, i);
sqlcom.ExecuteNonQuery();
}
ct.Commit();
}
catch (Exception ex)
{
ct.Rollback();
}
}
}

首先先宣告明確交易的CommittableTransaction物件

1
CommittableTransaction ct = new CommittableTransaction();

再將明確交易註冊到Connection

1
SQL.EnlistTransaction(ct);

EnlistTransaction:ADO.NET 2.0中的新功能獲得支援,以使用EnlistTransaction方法,登記在分散式交易中。由於在Transaction執行個體中登記連接,EnlistTransaction會利用System.Transactions命名空間中提供的功能,管理分散式交易,之後在SQLCommand中進行我們所需要的交易行為與SQL處理模式,當行為完成後再執行Commit()就可以進行資料寫入動作,若是中途發生Exception,也可以透過Rollback()將資料還原。

TransactionScope


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
string strSQL = "delete [dbo].[TestTB]";
using (TransactionScope ts = new TransactionScope())
{
using (SqlConnection SQL = new SqlConnection("data source=.;Initial Catalog=test;User ID=test;Password=1234"))
{
SQL.Open();
using (SqlCommand sqlcom = new SqlCommand())
{
try
{
sqlcom.Connection = SQL;
sqlcom.CommandText = strSQL;
sqlcom.ExecuteNonQuery();
for (int i = 0; i < 1000; i++)
{
sqlcom.CommandText = string.Format("insert into [dbo].[TestTB] (A,B,C,D,E,F,H) values ('A{0}','A{1}','A{2}','A{3}','A{4}','A{5}',{6})", i, i + 1, i + 2, i + 3, i + 4, i + 9, i);
sqlcom.ExecuteNonQuery();
}
ts.Complete();
}
catch (Exception ex)
{
}
}
}
}

使用TransactionScope後,使用Using宣告式在整個Connection包起來,在這範圍內撰寫相關與SQL有關的處理程序即可。由new陳述式執行個體化TransactionScope時,交易管理員會決定要參與哪個交易,一旦決定後,範圍永遠會參與該交易。此決策是根據兩個因素而定:環境交易是否存在,以及建構函式中的TransactionScopeOption參數值如果沒有任何例外狀況在交易範圍中發生 (也就是,在 TransactionScope 物件的初始化與呼叫其 Dispose 方法之間),則會允許範圍所參與的交易繼續。如果有例外狀況在交易範圍內發生,則會復原範圍所參與的交易。在這處理程序完畢後,只要在最後面加上Complete(),就可以完成此交易。若是沒有加入Complete(),則此交易將不被完成。

透過以上兩個方式,讓撰寫交易相關程式簡化許多