歡迎您光臨本站 註冊首頁

了解Linq to Sql中管理併發更新時的衝突(第二章)

←手機掃碼閱讀     火星人 @ 2014-03-09 , reply:0

    LINQ to DataSet 功能主要通過 DataRowExtensionsDataTableExtensions 類中的擴展方法公開.LINQ to DataSet 基於並使用現有的 ADO.NET 2.0 體系結構生成,在應用程序代碼中不能替換 ADO.NET 2.0.現有的 ADO.NET 2.0 代碼將繼續在 LINQ to DataSet 應用程序中有效.下圖闡釋了 LINQ to DataSet 與 ADO.NET 2.0 和數據存儲區的關係.

  無論與目前的ORM框架相比有沒有優勢,Linq to Sql在語言和平台的級別上為我們提供了一種新的操作對象和數據的方式,在一定程度上為我們解決了Object != Data的問題.在實際應用中,對於資料庫的操作往往有著天生的併發性,因此在更新數據時可能會產生衝突.有些時候,如果沒有合理的解決衝突問題,輕則讓用戶摸不著頭腦,重則讓系統數據處於一種不一致的狀態.Linq to Sql自然考慮到了這一點,本系列討論的內容,就是在使用Linq to Sql時,如何管理併發更新時產生的衝突.

  本文為這個系列的第一篇,將討論一些預備知識,它們是進行後續研究的基礎.
一些定義:

  首先,我們來看一些定義:

  併發(Concurrency):兩個或更多的用戶嘗試同時更新資料庫的同一條記錄.
  併發衝突(Concurrency Confilct):兩個或更多的用戶嘗試同時向同一條記錄的一個或多個欄位提交衝突的值.
  併發控制(Concurrency Control):解決併發衝突的技術.
  樂觀併發控制(Optimistic Concurrency Control):在提交當前事務之前,首先查看即將更新的記錄是否被別的事務所改變的一種技術.
  悲觀併發控制(Pessimistic Concurrency Control):為紀錄加鎖以阻止其他事務訪問某些記錄,以避免產生併發衝突的一種技術.

  Linq to Sql的對象模型使用樂觀併發控制的方式來發現和解決衝突問題.很顯然,它假設衝突發生的可能性並不大.如果您需要使用悲觀併發控制來解決衝突問題,則可以使用其他方法(例如自定義存儲過程供程序調用).

  調試方法:

  Linq to Sql的相當部分由編譯器來實現,而語言中的Linq語句最終會被轉化為Sql,因此如果要理解Linq to Sql的工作,一定要將操作中所執行的Sql語句給挖掘出來.一般來說,要挖掘出操作中所使用的Sql語句,可以使用以下幾種方法(以下將使用Sql Server 2005自帶的AdventureWorks資料庫來作為示例):

  1、獲取Query所對應的SqlCommand對象:
  在開發過程中,我們可以通過Query獲得對應的Sql Command對象.請看如下代碼:

AdventureWorksDataContext db = new AdventureWorksDataContext();
var products = from p in db.Products
 where p.ProductID == 3
 select new { p.ProductID, p.Name };
foreach (var p in products)
{
Console.WriteLine(p);
}

DbCommand cmd = db.GetCommand(products);
Console.WriteLine("------------");
Console.WriteLine("Command Text: n{0}", cmd.CommandText);

Console.WriteLine("------------");
Console.WriteLine("Command Type: n{0}", cmd.CommandType);

Console.WriteLine("------------");
Console.WriteLine("Command Parameters:");
foreach (DbParameter p in cmd.Parameters)
{
Console.WriteLine("{0}: {1}", p.ParameterName, p.Value);
}

Console.ReadLine();
  輸出結果如下:

Command Text:
SELECT [t0].[ProductID], [t0].[Name]
FROM [Production].[Product] AS [t0]
WHERE [t0].[ProductID] = @p0
------------
Command Type:
Text
------------
Command Parameters:
@p0: 3

  可以看到,無論是Sql語句或是參數都被列印了出來.事實上,由於我們得到了完整的SqlCommand對象,我們可以獲取的信息並不止上述這些.

  2、使用LINQ to SQL Debug Visualizer:
  使用LINQ to SQL Debug Visiualizer,我們可以在調試程序時直觀地獲得Query所對應的Sql語句以及參數,而不必獲得SqlCommand對象並列印信息.具體使用方法詳見Scott Gu的這篇博文.

  3、使用DataContext的Log功能:


  DataContext自帶的Log屬性為一個TextWriter類型的對象,如果我們設置了這個屬性,則DataContext所有的操作將會通過這個TextWriter對象輸出.與比上述兩種方法相比,這個方法的優勢在於DataContext所執行的所有語句,無論SELECT、INSERT、UPDATE或者是DELETE都會被輸出;而上面的兩種做法只能得到Query的信息,也就是SQL語句的SELECT操作.

  請看如下代碼,下面的代碼將AdventureWorksDataContext對象的所有操作輸出至Console:

AdventureWorksDataContext db = new AdventureWorksDataContext();
db.Log = Console.Out;
Product product = (from p in db.Products
where p.ProductID == 1
select p).First();

product.Name = "Hello World";
db.SubmitChanges();
Console.ReadLine();

  輸出結果如下:

SELECT TOP (1) [t0].[ProductID], [t0].[Name], [t0].[ProductNumber], [t0].[MakeFl
...
edDate], [t0].[rowguid], [t0].[ModifiedDate]
FROM [Production].[Product] AS [t0]
WHERE [t0].[ProductID] = @p0
-- @p0: Input Int (Size = 0; Prec = 0; Scale = 0) [1]
-- Context: SqlProvider(Sql2005) Model: AttributedMetaModel Build: 3.5.21004.1

UPDATE [Production].[Product]
SET [Name] = @p11
WHERE ([ProductID] = @p0) AND ([Name] = @p1) AND ([ProductNumber] = @p2) AND (NO
...
NULL) AND ([rowguid] = @p9) AND ([ModifiedDate] = @p10)
-- @p0: Input Int (Size = 0; Prec = 0; Scale = 0) [1]
...
-- @p11: Input NVarChar (Size = 11; Prec = 0; Scale = 0) [Hello World]
-- Context: SqlProvider(Sql2005) Model: AttributedMetaModel Build: 3.5.21004.1

  在這裡我省略了大部分的輸出,不過從上面的片斷中我們已經可以看到SELECT和UPDATE操作所使用的Sql語句以及參數都被列印了出來.這就是我們可以利用的調試信息.

  4、使用Sql Server Profiler:

  其實使用Sql Server Profile來監聽資料庫操作應該是最容易想到的方法.相信各位朋友對於Sql Server Profiler的簡單操作也已經非常熟悉,我在這裡就不贅述了.

  那麼第3中做法相比,使用Sql Server Profiler有什麼又優點和缺點呢?使用Sql Server Profiler的優點可能就在於方便,我們不用寫代碼,也不用設法將Log信息輸出至某個地方.缺點可能就在於Sql Server Profiler獲取到的信息會比較多,而其中只有一小部分是我們需要的.,Sql Server Profiler的輸出也不如DataContext的Log輸出來的工整、易讀.至於在開發過程中使用什麼做法比較合適,我這裡也無法推薦,這需要您根據實際情況進行選擇了.


[火星人 ] 了解Linq to Sql中管理併發更新時的衝突(第二章)已經有495次圍觀

http://coctec.com/docs/linux/show-post-58698.html