日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

在Linq to Sql中管理并发更新时的冲突(3):使用记录的时间戳进行检测

發布時間:2025/3/8 编程问答 38 豆豆
生活随笔 收集整理的這篇文章主要介紹了 在Linq to Sql中管理并发更新时的冲突(3):使用记录的时间戳进行检测 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
我們描述了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

Row not found or changed. 上面代碼中的UPDATE語句相信大家都很清楚其含義。不過這里可能還需要解釋其他兩個問題: 首先是那句SELECT語句。如果您去閱讀自動生成的Object Model的代碼時就會發現,record_version屬性上有一個ColumnAttribute標記(假設您使用了Attribute Based Mapping Source),其AutoSync屬性為Always,因此在任何操作之后,Linq to Sql都會補充一句SELECT語句,以此獲得新的數據并修改DataContext中的特定對象。其次,由于timestamp類型的數據在記錄被修改時就會設置,因此在更新時其他紀錄的值與之前相同,也會引發更新沖突,這一點和基于字段值比較的前一種方法是不同的。 那么,我們一直說出現了“并發更新沖突”,那么發生沖突后又會出現什么問題呢?我們來看一個略有些復雜的示例: try
{
LinqToSqlDemoDataContext?dataContext =?new?LinqToSqlDemoDataContext();

Order?order1 = dataContext.Orders.Single(o => o.OrderID == 1);
Order?order2 = dataContext.Orders.Single(o => o.OrderID == 2);
Order?order3 = dataContext.Orders.Single(o => o.OrderID == 3);

Console.WriteLine('Order 1: '?+ order1.Introduction);
Console.WriteLine('Order 2: '?+ order2.Introduction);
Console.WriteLine('Order 3: '?+ order3.Introduction);
Console.WriteLine();

order1.Introduction =?'Order 1 modified.';
order2.Introduction =?'Order 2 modified.';
order3.Introduction =?'Order 3 modified.';

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

LinqToSqlDemoDataContextdb =?new?LinqToSqlDemoDataContext();
Ordero1 = db.Orders.Single(o => o.OrderID == 1);
Ordero2 = db.Orders.Single(o => o.OrderID == 2);
Ordero3 = db.Orders.Single(o => o.OrderID == 3);

Console.WriteLine('Order 1: '?+ o1.Introduction);
Console.WriteLine('Order 2: '?+ o2.Introduction);
Console.WriteLine('Order 3: '?+ o3.Introduction);

Console.ReadLine(); 假設我們的數據表里有以下三條記錄:
OrderIDNameIntroductionrecord_version
1Order 1This is order 1<Binary data>
2Order 2This is order 2<Binary data>
3Order 3This is order 3<Binary data>
當程序進入到SubmitChanges語句的斷點時,我們去數據庫中運行以下代碼,以修改OrderID為2的記錄。 UPDATE?Order?SET?OrderID =?"New Order 2"?WHERE?OrderID = 2 繼續運行程序,最終控制臺中會打印出以下信息: Order 1: This is order 1
Order 2: This is order 2
Order 3: This is order 3

UPDATE [dbo].[Order]
SET [Introduction] = @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 = 26; Prec = 0; Scale = 0) [Order 1 modified.]
-- @p3: Input Int (Size = 0; Prec = 0; Scale = 0) [1]
-- Context: SqlProvider(Sql2005) Model: AttributedMetaModel Build: 3.5.21022.8

UPDATE [dbo].[Order]
SET [Introduction] = @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) [2]
-- @p1: Input Timestamp (Size = 8; Prec = 0; Scale = 0) [SqlBinary(8)]
-- @p2: Input NVarChar (Size = 26; Prec = 0; Scale = 0) [Order 2 modified.]
-- @p3: Input Int (Size = 0; Prec = 0; Scale = 0) [2]
-- Context: SqlProvider(Sql2005) Model: AttributedMetaModel Build: 3.5.21022.8

---------- 1 of 2 updates failed. ----------
Order 1: This is order 1
Order 2: This is order 2
Order 3: This is order 3 首先我們分別打印出三個Video對象的Introduction并將它們修改為新的值。在SubmitChanges方法調用之前,數據庫中ID為2的記錄已經被修改過了,因此在第一組UPDATE+SELECT調用成功之后——請注意,這是一次調用,Linq to Sql每次更新一條記錄——在更新第二條記錄之后發現了并發沖突。于是拋出異常(請注意異常的Message表示“兩次更新其中有一次失敗了”),第三條記錄也不會再更新了。在沖突發生之后,ID為2和紀錄自然沒有被修改(WHERE條件不成立),但是第一條記錄呢?從try...catch塊之后的操作中看,ID為1的記錄也沒有被更新。 也就是說,第一次更新被回滾了。這自然是事務的作用。在調用(默認的)SubmitChanges方法時,Linq to Sql會把所有的更新放在同一個事務中,因此它們“共同進退”。但是由于業務需求不同,有時候我們不希望某條記錄的沖突導致了所有更新失敗。自然,Linq to Sql也提供了這個方面的控制。在下一篇文章中,我們就來看一下Linq to Sql中與樂觀并發控制有關的事務問題,以及出現并發沖突之后的解決方式。

本文轉自 jeffz 51CTO博客,原文鏈接:http://blog.51cto.com/jeffz/59516,如需轉載請自行聯系原作者

總結

以上是生活随笔為你收集整理的在Linq to Sql中管理并发更新时的冲突(3):使用记录的时间戳进行检测的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。