當單一業務操作橫跨多個資料庫、多台伺服器,或需包含非資料庫資源(如訊息佇列、檔案系統)時,單一資料庫交易已無法滿足 ACID 需求。.NET Framework 提供 System.Transactions 命名空間,配合 Microsoft Distributed Transaction Coordinator (MSDTC),可輕鬆實現分散式交易。本文詳細說明核心用法、常見陷阱與環境設定。
// 業務邏輯:MethodA 成功才執行 MethodB,任一失敗全數回滾
int iGet = MethodA();
if (iGet > 0)
{
MethodB(); // 可能拋出例外或回傳失敗
}
若 MethodA 寫入資料庫 A,MethodB 寫入資料庫 B(或同資料庫不同連線),需分散式交易保證一致性。
using System.Transactions;
public void ExecuteBusinessLogic()
{
// 預設隔離級別:Serializable(最高,效能較低)
// 可透過 TransactionOptions 調整 IsolationLevel
using (TransactionScope scope = new TransactionScope())
{
try
{
int iGet = MethodA();
if (iGet > 0)
{
MethodB();
}
// 關鍵:明確呼叫 Complete() 才會提交交易
scope.Complete();
}
catch (Exception ex)
{
// 記錄日誌、拋出或處理
// 若未呼叫 Complete(),Dispose 時自動回滾
throw;
}
} // scope.Dispose() 隱式回滾(若未 Complete)
}
SqlConnection 區域交易;偵測到第二個連線或跨資源管理員時,自動升級為 MSDTC 管理的分散式交易。try-catch 內部例外若未吞沒,scope.Dispose() 會觸發回滾。若捕獲後不重拋,需手動決定是否 Complete()。TransactionScopeOption.Required 會重用外層交易;可用 RequiresNew 強制建立獨立交易。分散式交易在開發機單機常能跑通,部署至多台伺服器頻繁失敗。請依序檢查:
dcomcnfg → 元件服務 → 電腦 → 我的電腦 → 右鍵內容 → MSDTC 標籤 → 安全性設定net stop msdtc && net start msdtcping <對方 NetBIOS 名稱> 與 ping <IP>C:\Windows\System32\drivers\etc\hosts 含正確對應:192.168.1.15 ServerB
192.168.1.10 ServerA
MSDTC 使用 RPC 動態連接埠,防火牆需開放 135 (RPC Endpoint Mapper) 及 動態連接埠範圍(預設 49152-65535),或透過 netsh int ipv4 set dynamicport tcp start=50000 num=1000 限制範圍並開放該範圍。
DTCPing.exe,一端作 Server,一端作 Client,觀察「RPC test successful」訊息。var options = new TransactionOptions
{
IsolationLevel = IsolationLevel.ReadCommitted, // 降低隔離級別提升並發
Timeout = TimeSpan.FromMinutes(2) // 超時時間
};
using (var scope = new TransactionScope(TransactionScopeOption.Required, options))
{
// ...
}
實作 IEnlistmentNotification 介面,將自訂資源(如檔案操作、Web API 呼叫)納入交易管理:
public class FileTransaction : IEnlistmentNotification
{
public void Prepare(PreparingEnlistment preparingEnlistment) { /* 備份檔案 */ }
public void Commit(Enlistment enlistment) { /* 確認刪除備份 */ }
public void Rollback(Enlistment enlistment) { /* 還原備份 */ }
public void InDoubt(Enlistment enlistment) { /* 不確定狀態處理 */ }
}
// 使用時
Transaction.Current.EnlistVolatile(new FileTransaction(), EnlistmentOptions.None);
System.Transactions 於 .NET Core 2.0+ 重新引入,但 僅支援 Windows(依賴 MSDTC)。| 錯誤現象 | 可能原因 | 解決方向 |
|---|---|---|
MSDTC on server 'X' is unavailable | MSDTC 服務未啟動/防火牆阻擋/RPC 連接埠未開 | 檢查服務、防火牆 135+動態埠、DTCPing 測試 |
The transaction has already been implicitly or explicitly committed or aborted | 巢狀 Scope 邏輯錯誤/連線池導致連線重用 | 檢查 TransactionScopeOption 設定、確保連線在 Scope 內開啟 |
| 交易未回滾 | 忘記呼叫 scope.Complete() / 吞沒例外 | 代碼審查、加上 try-catch 重拋 |
| 效能極差 | 預設 Serializable 隔離級別/長時間持有交易 | 降級至 ReadCommitted、縮小 Scope 範圍、避免交易中呼叫外部 API |
TransactionScope 讓分散式交易編碼極簡單,但環境設定才是成敗關鍵。開發階段務必在測試環境驗證跨機器案例,上線前用 DTCPing 全流程驗證。現代雲原生架構下,若跨平台或微服務化,建議評估 Saga/事件驅動替代方案,降低對 MSDTC 的強依賴。