1. 程式人生 > >基於多活動結果集(Multiple Active Result Sets,簡稱MARS)的C#示例分析

基於多活動結果集(Multiple Active Result Sets,簡稱MARS)的C#示例分析

    本示例將展示怎樣從資料庫中讀取一個SalesOrder,然後減少已賣出的專案的庫存數額。典型地,這將要求建立到資料庫的兩個順序連線-一個用於讀取售出的專案數額,另一個用於使用減少的數額來更新庫存。
  下面的程式碼片斷顯示了怎樣在不使用MARS功能的情況下達到這一目的。
   ArrayList ids = new ArrayList();
ArrayList qtys = new ArrayList();
string connectionString = "Data Source=MEDIACENTER;" +
 "Initial Catalog=AdventureWorks;Integrated Security=SSPI;" +
 "MultipleActiveResultSets=False";
string strSQLGetOrder = "Select * from Sales.SalesOrderDetail" +
 "WHERE SalesOrderID = 43659";
SqlConnection readConnection = new SqlConnection(connectionString);
readConnection.Open();
SqlCommand readCommand =new SqlCommand(strSQLGetOrder, readConnection);
using (SqlDataReader rdr = readCommand.ExecuteReader()){
 while (rdr.Read()){
  ids.Add(rdr["ProductID"]);
  qtys.Add(rdr["OrderQty"]);
 }
}
readConnection.Close();
string strSQLUpdateInv = "UPDATE Production.ProductInventory " +
 "SET Quantity=Quantity-@amt WHERE (ProductID=@pid)";
SqlConnection writeConnection = new SqlConnection(connectionString);
writeConnection.Open();
SqlCommand writeCommand = new SqlCommand(strSQLUpdateInv,writeConnection);
writeCommand.Parameters.Add("@amt",SqlDbType.Int);
writeCommand.Parameters.Add("@pid",SqlDbType.Int);
for(int lp=0;lp<ids.Count;lp++){
 writeCommand.Parameters["@amt"].Value=qtys[lp];
 writeCommand.Parameters["@pid"].Value=ids[lp];
 writeCommand.ExecuteNonQuery();
}
writeConnection.Close();
     這個示例從資料庫中讀取單個銷售訂單(這裡,訂單號43659被硬編碼)-該庫中有一專案列表。這些專案應該從庫存中扣除,而這是通過第二個連線完成的。然而,為了建立在第二個連線上的正確查詢-從相應的產品中扣除正確的數量-要求第一個查詢的結果在記憶體中被緩衝。並且在這個示例中這是通過使用兩個陣列列表來完成的。這裡的明顯耗費是:如果假定這是一個高度擁擠的網站,那麼我們需要大量的緩衝記憶體來處理這些最終要被扔掉的數值。
  為此,你還有另外一個方法-通過同時開啟兩個連線並且使用從一連線中讀取的資料結果-該連線被直接傳遞到在第二個連線上的更新命令;但是仍存在在開啟多個連線時記憶體和資料庫方面的代價。典型地,資料庫連線對於一個應用程式來說比記憶體具有更高的代價,所以這裡使用了順序連線方式。
  MARS提供瞭解決這個問題的在以上兩個方面均能達到最優的方法。你可以保持單個連線開啟著,從而減少了到資料庫的所有連線。這樣以來,你就不需要用一個記憶體變數來儲存讀取的結果。
  而且,該MARS程式碼也為更短並且因此更易於讀取和維護。下面的程式碼片斷展示了在相同的操作上使用MARS的情況:
string connectionString = "Data Source=MEDIACENTER;" +
 "Initial Catalog=AdventureWorks;Integrated Security=SSPI;" +
 "MultipleActiveResultSets=True";
string strSQLGetOrder = "Select * from Sales.SalesOrderDetail" +
 "WHERE SalesOrderID = 43659";
string strSQLUpdateInv = "UPDATE Production.ProductInventory " +
 "SET Quantity=Quantity-@amt WHERE (ProductID=@pid)";
SqlConnection marsConnection = new SqlConnection(connectionString);
marsConnection.Open();
SqlCommand readCommand = new SqlCommand(strSQLGetOrder, marsConnection);
SqlCommand writeCommand = new SqlCommand(strSQLUpdateInv, marsConnection);
writeCommand.Parameters.Add("@amt", SqlDbType.Int);
writeCommand.Parameters.Add("@pid", SqlDbType.Int);
using (SqlDataReader rdr = readCommand.ExecuteReader()){
 while (rdr.Read()){
  writeCommand.Parameters["@amt"].Value = rdr["OrderQty"];
  writeCommand.Parameters["@pid"].Value = rdr["ProductID"];
  writeCommand.ExecuteNonQuery();
 }
}
marsConnection.Close();
      正如你所見,這裡的方式在記憶體和資料庫連線方面比上一個示例更易於讀取和管理且更為有效。並且,在這種情況中,只讀取一次,隨後跟著的是寫操作;在某種典型情形下你的不使用MARS功能的程式碼有可能更為複雜,並因此使得MARS為你帶來的節省更為明顯。
  儘管MARS便利了在同一個連線上的多重活動結果集的操作,但是在這些結果集上的操作仍然是序列執行的;如果你要求並行處理資料,那麼多連線還是必需的。而且,請注意,一個使用了MARS功能的連線要比不使用的連線將利用更多些的資源。當然,從長遠來看,你卻節約了資源-由於你可以在同一個連線上執行多個命令;但是如果你在不需要的地方使用了MARS(也就是,如果你只需要單個結果集),你將會嚴重地影響系統性能。因此,如果你是在基於多資料庫連線構建一個應用程式,那麼你必須認真考慮哪些連線需要MARS,而哪些連線不需要-為了最大限度地利用資源。