TransactionScope分散式事務
下列程式碼就是一個正在建立的事務,這個事務自身還封裝了多個數據庫查詢。只要任意一個 SqlCommand 物件引發異常,程式流控制就會跳出 TransactionScope 的 using 語句塊,隨後,TransactionScope 將自行釋放並回滾該事務。由於這段程式碼使用了 using 語句,所以 SqlConnection 物件和 TransactionScope 物件都將被自動呼叫Dispose()釋放。由此可見,只需新增很少的幾行程式碼,您就可以構建出一個事務模型,這個模型可以對異常進行處理,執行結束後會自行清理,此外,它還可以對命令的提交或回滾進行管理。
//建立TransactionScopeusing (TransactionScope tsCope =new TransactionScope())
{
using (SqlConnection cn2005 =new SqlConnection(someSql2005))
{
SqlCommand cmd =new SqlCommand(sqlUpdate, cn2005);
cn2005.Open();
cmd.ExecuteNonQuery();
}
using (SqlConnection cn2005 =new SqlConnection(anotherSql2005))
{
SqlCommand cmd =new
cn2005.Open();
cmd.ExecuteNonQuery();
}
tsCope.Complete();
} 複製程式碼
連線字串關鍵字(Enlist)
SqlConnection.ConnectionString 屬性支援關鍵字 Enlist,該關鍵字指示 System.Data.SqlClient 是否將檢測事務上下文並自動在分散式事務中登記連線。 如果 Enlist=true,連線將自動在開啟的執行緒的當前事務上下文中登記。 如果 Enlist=false,SqlClient 連線不會與分散式事務進行互動。 Enlist 的預設值為 true。 如果連線字串中未指定 Enlist,若在連線開啟時檢測到一個,連線將自動在分散式事務中登記。
上面所看到的示例中我們使用了TransactionScope的預設設定。TransactionScope有三種模式:
TransactionScopeOptions | 描述 |
Required | 如果已經存在一個事務,那麼這個事務範圍將加入已有的事務。否則,它將建立自己的事務。 |
RequiresNew | 這個事務範圍將建立自己的事務。 |
Suppress | 如果處於當前活動事務範圍內,那麼這個事務範圍既不會加入氛圍事務 (ambient transaction),也不會建立自己的事務。當部分程式碼需要留在事務外部時,可以使用該選項。 |
若要更改 TransactionScope 類的預設設定,您可以建立一個 TransactionOptions 物件,然後通過它在 TransactionScope 物件上設定隔離級別和事務的超時時間。TransactionOptions 類有一個 IsolationLevel 屬性,通過這個屬性可以更改隔離級別,例如從預設的可序列化 (Serializable) 改為ReadCommitted,甚至可以改為 SQL Server 2005 引入的新的快照 (Snapshot) 級別。(請記住,隔離級別僅僅是一個建議。大多數資料庫引擎會試著使用建議的隔離級別,但也可能選擇其他級別。)此外,TransactionOptions 類還有一個 TimeOut 屬性,這個屬性可以用來更改超時時間(預設設定為 1 分鐘)。
下列程式碼中使用了預設的 TransactionScope 物件及其預設建構函式。也就是說,它的隔離級別設定為可序列化 (Serializable),事務的超時時間為 1 分鐘,而且 TransactionScopeOptions 的設定為 Required。 TransactionOptions tOpt =new TransactionOptions();
//設定TransactionOptions模式tOpt.IsolationLevel = IsolationLevel.ReadCommitted;
// 設定超時間隔為2分鐘,預設為60秒tOpt.Timeout =new TimeSpan(0, 2, 0);
string cnString = ConfigurationManager.ConnectionStrings["sql2005DBServer"].ConnectionString);
using (TransactionScope tsCope =new TransactionScope(TransactionScopeOption.RequiresNew, tOpt))
{
using (SqlConnection cn2005 =new SqlConnection(cnString)
{
SqlCommand cmd =new SqlCommand(updateSql1, cn2005);
cn2005.Open();
cmd.ExecuteNonQuery();
}
tsCope.Complete();
} 複製程式碼
巢狀應用
如下列程式碼,假設 Method1 建立一個 TransactionScope,針對一個數據庫執行一條命令,然後呼叫 Method2。Method2 建立一個自身的 TransactionScope,並針對一個數據庫執行另一條命令。
{
using (TransactionScope ts =new TransactionScope(TransactionScopeOption.Required))
{
using (SqlConnection cn2005 =new SqlConnection())
{
SqlCommand cmd =new SqlCommand(updateSql1, cn2005);
cn2005.Open();
cmd.ExecuteNonQuery();
}
Method2();
ts.Complete();
}
}
privatevoid Method2()
{
using (TransactionScope ts =new TransactionScope(TransactionScopeOption.RequiresNew))
{
using (SqlConnection cn2005 =new SqlConnection())
{
SqlCommand cmd =new SqlCommand(updateSql2, cn2005);
cn2005.Open();
cmd.ExecuteNonQuery();
}
ts.Complete();
}
} 複製程式碼
總結:
進入和退出事務都要快,這一點非常重要,因為事務會鎖定寶貴的資源。最佳實踐要求我們在需要使用事務之前再去建立它,在需要對其執行命令前迅速開啟連線,執行動作查詢 (Action Query),並儘可能快地完成和釋放事務。在事務執行期間,您還應該避免執行任何不必要的、與資料庫無關的程式碼,這能夠防止資源被毫無疑義地鎖定過長的時間。