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

LINQ to SQL 並發衝突管理 (2):深入剖析更新衝突檢測機制

     編輯:關於.NET

承接前文並發控制概念與 SQL 觀察方法,本文詳細檢視 LINQ to SQL 如何發現並發更新衝突。

測試環境:簡單 Video 資料表

Video 資料表結構
Video 表:VideoID (PK, int, identity)、Introduction (nvarchar(max), not null)、SiteID (int, not null)

初始資料:

VideoID | Introduction | SiteID
1       | Introduction 1 | 1

正常更新流程與產生 SQL

LinqToSqlDemoDataContext dataContext = new LinqToSqlDemoDataContext();
dataContext.Log = Console.Out;
Video video = dataContext.Videos.Single(v => v.VideoID == 1);
video.Introduction = "1235";
dataContext.SubmitChanges();

輸出 SQL:

SELECT [t0].[VideoID], [t0].[Introduction], [t0].[SiteID]
FROM [dbo].[Video] AS [t0]
WHERE [t0].[VideoID] = @p0

UPDATE [dbo].[Video]
SET [Introduction] = @p3
WHERE ([VideoID] = @p0) AND ([Introduction] = @p1) AND ([SiteID] = @p2)
-- @p0: 1, @p1: Introduction 1, @p2: 1, @p3: 1235

核心機制:樂觀並發控制

UPDATE 陳述式 WHERE 條件包含 主鍵 + 所有原始欄位值。只有當「更新時」資料列狀態與「讀取時」完全一致,更新才成功。這就是樂觀並發控制 —— 直到更新時才判斷並發問題。

嚴格來說,這只是樂觀並發控制的一部分,完整還包含衝突發生後的「處理問題」過程。

特點:不關心記錄是否「被修改過」,只比較狀態是否相同 (可能記錄被修改但數值未變)。

製造並發衝突實驗

try
{
    LinqToSqlDemoDataContext dataContext = new LinqToSqlDemoDataContext();
    Video video = dataContext.Videos.Single(v => v.VideoID == 1);
    // 中斷點:在此處透過 SQL 修改資料庫記錄
    video.Introduction = "12356";
    dataContext.SubmitChanges();
}
catch (ChangeConflictException e)
{
    Console.WriteLine(e.Message);
}
Console.ReadLine();

中斷點處執行 UPDATE Video SET SiteID = 10 WHERE VideoID = 1,繼續執行拋出異常:

Row not found or changed.

原因:WHERE 條件不滿足,ExecuteNonQuery 回傳 0,LINQ to SQL 偵測到記錄被修改或刪除。

Attach 方法的特殊行為

LinqToSqlDemoDataContext dataContext = new LinqToSqlDemoDataContext();
dataContext.Log = Console.Out;
Video video = new Video();
video.VideoID = 1;
dataContext.Videos.Attach(video, false);
video.Introduction = "123";
dataContext.SubmitChanges();

產生 SQL:

UPDATE [dbo].[Video]
SET [Introduction] = @p0
WHERE 0 = 1
-- @p0: 123

WHERE 0 = 1 永不成立,無記錄更新,同樣拋出 ChangeConflictException。Attach 方法與第二個參數 false (表示未修改) 導致 LINQ to SQL 無法取得原始值進行並發檢查。

反思與預告

此種「逐欄位比對」樂觀並發控制是否顯得累贅?下文將探討更優雅的 Timestamp 機制。

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