1. 程式人生 > >TransactionScope分散式事務

TransactionScope分散式事務

  TransactionScope是.Net Framework 2.0滯後,新增了一個名稱空間。它的用途是為資料庫訪問提供了一個“輕量級”[區別於:SqlTransaction]的事物。使用之前必須新增對 System.Transactions.dll 的引用。

      下列程式碼就是一個正在建立的事務,這個事務自身還封裝了多個數據庫查詢。只要任意一個 SqlCommand 物件引發異常,程式流控制就會跳出 TransactionScope 的 using 語句塊,隨後,TransactionScope 將自行釋放並回滾該事務。由於這段程式碼使用了 using 語句,所以 SqlConnection 物件和 TransactionScope 物件都將被自動呼叫Dispose()釋放。由此可見,只需新增很少的幾行程式碼,您就可以構建出一個事務模型,這個模型可以對異常進行處理,執行結束後會自行清理,此外,它還可以對命令的提交或回滾進行管理。 

//建立TransactionScope

using (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
 SqlCommand(sqlDelete, cn2005);
    cn2005.Open();
    cmd.ExecuteNonQuery();
  }


  tsCope.Complete();
}
複製程式碼

   連線字串關鍵字(Enlist)
      SqlConnection.ConnectionString 屬性支援關鍵字 Enlist,該關鍵字指示 System.Data.SqlClient 是否將檢測事務上下文並自動在分散式事務中登記連線。 如果 Enlist=true,連線將自動在開啟的執行緒的當前事務上下文中登記。 如果 Enlist=false,SqlClient 連線不會與分散式事務進行互動。 Enlist 的預設值為 true。 如果連線字串中未指定 Enlist,若在連線開啟時檢測到一個,連線將自動在分散式事務中登記。  

Server=(local)SQL2005;Database=Northwind;Integrated Security=SSPI;auto-enlist=false

       上面所看到的示例中我們使用了TransactionScope的預設設定。TransactionScope有三種模式:

TransactionScopeOptions 描述
Required 如果已經存在一個事務,那麼這個事務範圍將加入已有的事務。否則,它將建立自己的事務。
RequiresNew 這個事務範圍將建立自己的事務。
Suppress 如果處於當前活動事務範圍內,那麼這個事務範圍既不會加入氛圍事務 (ambient transaction),也不會建立自己的事務。當部分程式碼需要留在事務外部時,可以使用該選項。
      您可以在程式碼的任何位置上隨是檢視是否存在事務範圍,具體方法就是檢視 System.Transactions.Transaction.Current 屬性。如果這個屬性為“null”,說明不存在當前事務。
      若要更改 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(020);
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,並針對一個數據庫執行另一條命令。      

privatevoid Method1()
{
  
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),並儘可能快地完成和釋放事務。在事務執行期間,您還應該避免執行任何不必要的、與資料庫無關的程式碼,這能夠防止資源被毫無疑義地鎖定過長的時間。