交易 (Transaction) 是資料庫操作的原子單位,滿足 ACID 特性。LINQ to SQL 提供三種交易建立方式,本文系統化解析各模式適用場景與代碼範例。
var ctx = new NorthwindDataContext();
var c1 = new Customer { CustomerID = "TESTA", CompanyName = "testa's company" };
var c2 = new Customer { CustomerID = "TESTBC", CompanyName = "testb's company" }; // ID 長度 6,超過 DB 限制 5
ctx.Customers.InsertOnSubmit(c1);
ctx.Customers.InsertOnSubmit(c2);
ctx.SubmitChanges(); // 內部自動開啟 ReadCommitted 交易
c2 違反 CHECK (LEN(CustomerID) <= 5) 約束 → 拋出 SqlException。SubmitChanges() 即可完成的業務單元。
var ctx = new NorthwindDataContext();
ctx.Transaction = ctx.Connection.BeginTransaction(IsolationLevel.Serializable);
try
{
ctx.SubmitChanges();
ctx.Transaction.Commit();
}
catch
{
ctx.Transaction.Rollback();
throw;
}
finally
{
ctx.Transaction = null; // 釋放連線回連線池
}
Commit/Rollback 並清空 ctx.Transaction,否則連線無法正確歸還連線池。SubmitChanges 需在同一交易中。
using (var scope = new TransactionScope())
{
var ctx = new NorthwindDataContext();
ctx.SubmitChanges();
// 同一 Scope 內可跨多個 DataContext、甚至跨資料庫 (需 MSDTC)
var ctx2 = new AnotherDataContext();
ctx2.SubmitChanges();
scope.Complete(); // 標記成功,離開 using 時自動 Commit
}
// 隱式 Rollback 若未呼叫 Complete()
using (var scope = new TransactionScope())
{
var ctx = new NorthwindDataContext();
ctx.ExecuteCommand("EXEC sp_ComplexLogic1");
ctx.ExecuteCommand("EXEC sp_ComplexLogic2");
ctx.ExecuteCommand("EXEC sp_ComplexLogic3");
ctx.SubmitChanges(); // 實體變更與 SP 執行在同一交易
scope.Complete();
}
ExecuteCommand、SubmitChanges、多個 DataContext **自動登記** 至同一環境交易。Serializable,可透過 TransactionScopeOption、TransactionOptions 調整。| 維度 | 預設隱式 | DataContext.Transaction | TransactionScope |
|---|---|---|---|
| 程式碼複雜度 | 最低 (零配置) | 中 (手動 Commit/Rollback) | 低 (using 區塊) |
| 隔離等級控制 | 固定 ReadCommitted | 完全可控 | 可配置 (預設 Serializable) |
| 跨 DataContext | 不支援 | 不支援 (單一連線) | 支援 (環境交易) |
| 跨資料庫/分散式 | 不支援 | 不支援 | 支援 (需 MSDTC) |
| 混合 ExecuteCommand | 不支援 (獨立交易) | 不支援 | 支援 |
| 例外安全 | 自動 Rollback | 需 try/finally | 自動 Rollback (using) |
| 推薦場景 | 簡單單一 SubmitChanges | 特殊隔離等級需求 | 現代應用首選 |
finally 設 ctx.Transaction = null,導致連線永佔不釋放。TransactionScopeOption.Required 會加入現有交易,若內層 Complete() 外層未 Complete(),整體仍回滾。TransactionScope 預設 **不流動** 至其他執行緒 (需 TransactionScopeAsyncFlowOption.Enabled .NET 4.5.1+)。Serializable 範圍鎖極易造成死鎖,高併發場景建議 ReadCommittedSnapshot (RCSI) + ReadCommitted。現代 LINQ to SQL 應用 **首選 TransactionScope**:語法簡潔、自動管理生命週期、支援跨 DataContext/資料庫、混合 ExecuteCommand。僅在需精細控制隔離等級或舊版 .NET 無 System.Transactions 時,考慮手動 DataContext.Transaction。預設隱式交易僅適合最簡單的單一 SubmitChanges 場景。