LINQ to SQL 在語言與平台層面提供全新操作資料方式,緩解 Object != Data 問題。實際應用中資料庫操作天生具並發性,更新時可能產生衝突。未合理解決衝突,輕則讓用戶困惑,重則導致資料不一致。本系列探討 LINQ to SQL 如何管理並發更新衝突,首篇奠基核心概念與除錯技巧。
| 術語 | 定義 |
|---|---|
| 並發 | 兩個或更多用戶嘗試同時更新資料庫同一筆記錄 |
| 並發衝突 | 多用戶嘗試向同一記錄的一或多個欄位提交衝突值 |
| 並發控制 | 解決並發衝突的技術 |
| 樂觀並發控制 | 提交前檢視即將更新記錄是否被其他交易修改 |
| 悲觀並發控制 | 鎖定記錄阻止其他交易存取,避免衝突產生 |
LINQ to SQL 採用 樂觀並發控制,假設衝突機率低。需悲觀控制時可用自訂預存程序等替代方案。
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("Command Text:\n{0}", cmd.CommandText);
Console.WriteLine("Command Type:\n{0}", cmd.CommandType);
foreach (DbParameter p in cmd.Parameters)
Console.WriteLine("{0}: {1}", p.ParameterName, p.Value);
輸出完整 SQL 與參數:
Command Text:
SELECT [t0].[ProductID], [t0].[Name]
FROM [Production].[Product] AS [t0]
WHERE [t0].[ProductID] = @p0
Command Type: Text
@p0: 3
Visual Studio 內建視覺化工具,偵錯時直觀查看 Query 對應 SQL 與參數,無需程式碼輸出。詳見 Scott Guthrie 部落格教學。
Log 為 TextWriter 類型,設定後 所有操作 (SELECT/INSERT/UPDATE/DELETE) 皆輸出,優於前兩法僅能觀察 SELECT。
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();
輸出包含 SELECT 與 UPDATE 完整 SQL 與參數:
SELECT TOP (1) [t0].[ProductID], [t0].[Name], ... FROM [Production].[Product] ...
UPDATE [Production].[Product] SET [Name] = @p11 WHERE ([ProductID] = @p0) AND ([Name] = @p1) ...
監聽資料庫操作最直觀方法,優點免寫程式碼,缺點資訊過多且不如 Log 輸出工整易讀。視專案需求選擇適合方式。