在Linq to Sql中管理并發更新時的沖突(3):使用記錄的時間戳進行檢測

作者: Jeffrey Zhao  來源: 博客園  發布時間: 2008-09-20 01:04  閱讀: 4573 次  推薦: 0   原文鏈接   [收藏]  
 
摘要:Linq to Sql提供了另外一種檢測并發更新沖突的方式:使用記錄的時間戳。
[1] 使用時間戳1
[2] 使用時間戳2
[3] 使用時間戳3

在《在Linq to Sql中管理并發更新時的沖突(2):引發更新沖突》一文中,我們描述了Linq to Sql檢測在更新時是否產生了沖突的基本方法:將該記錄每個字段原來的值和更新時的值進行對比,如果稍有不同則意味著記錄被修改過,因此產生了更新沖突。不過您是否有這樣的感覺,這種方法實在累贅了一些?如果一個表中有數十個字段,那么更新就必須完整地檢測一遍(不過我會在今后的文章中提到這方面的控制)。再者,如果其中某一個字段儲存了洋洋灑灑上萬字的文章,那么在驗證時僅僅是將它從Web服務器發送到數據庫服務器就需要耗費可觀的帶寬與時間,這是不是顯得有些“得不償失”呢?

因此Linq to Sql提供了另外一種檢測并發更新沖突的方式:使用記錄的時間戳。這并不是Linq to Sql特有的功能,如果您了解其他的ORM框架的話,就會發現諸如Hibernate也提供了類似的機制——自然,在使用上不會像Linq to Sql那樣方便。

在Sql Server中設計數據表時,我們可以使用一個特殊的數據類型:timestamp。請不要將它與SQL-2003標準中的timestamp類型混淆起來,那里的timestamp和Sql Server中的datetime比較相似(Oracle中timestamp的概念符合SQL-2003標準,而MySql中timestamp的概念與Sql Server相同),而Sql Server中的timestamp與SQL-2003標準中的rowversion類型對應。Sql Server中的timestamp類型和binary(8)在存儲上非常類似(不過nullable的timestamp和nvarchar(8)類似),從類型名稱上我們就可以看出,這是一個“時間戳”字段:當數據表中的某一條記錄被添加或者修改之后,Sql Server會自動向類型為timestamp的字段寫入當前時間。換句話說,只要在更新時發現該字段的值沒有被修改過,就表明沒有產生并發沖突。

我們還是通過一個例子來體驗一下吧。

 

如上圖。我們定義了一個新的數據表,其中有個record_version字段為timestamp類型,這就是記錄的時間戳(record_version這個字段名似乎有點不太“雅觀”,我覺得我們不會去主動使用它,所以問題不大——當然一些靜態檢查工具可不這么認為:))。有了記錄的時間戳,我們就可以在檢測更新沖突時獲得更好的性能了。

try
{
 LinqToSqlDemoDataContext dataContext = new LinqToSqlDemoDataContext();

    Order order = dataContext.Orders.Single(o => o.OrderID == 1);
    order.Name = "New Order Name";

    dataContext.Log = Console.Out;
    // 在下面的語句上設置一個斷點
    dataContext.SubmitChanges();
}
catch (ChangeConflictException e)
{
    Console.WriteLine(e.Message);
}

Console.ReadLine(); 

在最后的語句上設置斷點,并且在程序運行至斷點后去數據庫里對OrderID為1的紀錄作任意更新。然后按F5繼續運行:

UPDATE [dbo].[Order]
SET [Name] = @p2
WHERE ([OrderID] = @p0) AND ([record_version] = @p1)

SELECT [t1].[record_version]
FROM [dbo].[Order] AS [t1]
WHERE ((@@ROWCOUNT) > 0) AND ([t1].[OrderID] = @p3)
-- @p0: Input Int (Size = 0; Prec = 0; Scale = 0) [1]
-- @p1: Input Timestamp (Size = 8; Prec = 0; Scale = 0) [SqlBinary(8)]
-- @p2: Input NVarChar (Size = 14; Prec = 0; Scale = 0) [New Order Name]
-- @p3: Input Int (Size = 0; Prec = 0; Scale = 0) [1]
-- Context: SqlProvider(Sql2005) Model: AttributedMetaModel Build: 3.5.21022.8

上面代碼中的UPDATE語句相信大家都很清楚其含義。不過這里可能還需要解釋其他兩個問題:

首先是那句SELECT語句。如果您去閱讀自動生成的Object Model的代碼時就會發現,record_version屬性上有一個ColumnAttribute標記(假設您使用了Attribute Based Mapping Source),其AutoSync屬性為Always,因此在任何操作之后,Linq to Sql都會補充一句SELECT語句,以此獲得新的數據并修改DataContext中的特定對象。其次,由于timestamp類型的數據在記錄被修改時就會設置,因此在更新時其他紀錄的值與之前相同,也會引發更新沖突,這一點和基于字段值比較的前一種方法是不同的。

0
0
 
標簽:LINQ to SQL
 
 

文章列表

arrow
arrow
    全站熱搜
    創作者介紹
    創作者 大師兄 的頭像
    大師兄

    IT工程師數位筆記本

    大師兄 發表在 痞客邦 留言(0) 人氣()