首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> 關於.NET

LINQ to SQL 並發衝突管理 (3):使用 Timestamp 時間戳記優化衝突檢測

     編輯:關於.NET

前文介紹 LINQ to SQL 透過比對每個欄位原始值檢測並發衝突,但此法有缺點:欄位多時檢測繁瑣,大型文字欄位 (如文章內容) 驗證時須傳輸龐大資料,頗為「得不償失」。

LINQ to SQL 提供替代方案:使用資料列版本戳記。這非 LINQ to SQL 專有,Hibernate 等 ORM 亦有類似機制。

SQL Server Timestamp 資料類型

設計資料表時可使用 timestamp 類型。勿與 SQL-2003 標準 timestamp (類似 datetime) 混淆,SQL Server timestamp 對應 SQL-2003 rowversion,儲存類似 binary(8)。每當資料列新增或修改,SQL Server 自動寫入當前時間戳記。更新時若發現該欄位值未變,即表示無並發衝突。

資料表結構含 timestamp 欄位 Object Relational Designer 視圖
定義含 record_version timestamp 欄位的資料表

實戰驗證:Timestamp 機制運作

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 的記錄,繼續執行產生 SQL:

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 [1]
-- @p1: Input Timestamp [SqlBinary(8)]
-- @p2: Input NVarChar [New Order Name]
-- @p3: Input Int [1]

關鍵觀察點

  1. WHERE 條件包含 record_version,僅比對此欄位而非所有欄位
  2. SELECT 取回新 timestamp:因 ColumnAttribute 標記 AutoSync = Always,操作後自動同步
  3. 若其他欄位值相同但 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);
    // 列印原始 Introduction...
    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 + " ----------");
}
// 重新查詢驗證資料庫狀態...

中斷點處修改 OrderID=2 的記錄,執行結果:

Order 1: This is order 1
Order 2: This is order 2
Order 3: This is order 3
UPDATE ... OrderID=1 成功
UPDATE ... OrderID=2 失敗 (timestamp 不符)
---------- 1 of 2 updates failed. ----------
Order 1: This is order 1
Order 2: This is order 2
Order 3: This is order 3

重要發現

  • 第一筆更新成功,第二筆失敗拋出異常,第三筆未執行
  • 異常訊息指出「2 次更新其中 1 次失敗」
  • 第一筆成功的更新被回滾:預設 SubmitChanges 將所有更新置於同一交易,「共同進退」
  • 資料庫中 OrderID=1 記錄未實際修改

下一步預告

業務需求可能不希望單筆衝突導致全盤失敗。LINQ to SQL 提供交易控制與衝突解決機制,下文將深入探討樂觀並發控制相關交易議題與衝突解決方式。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved