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

分散式事務深度解析 (三):System.Transactions 依賴事務與 TransactionScope 完整實戰

     編輯:關於.NET

回顧:可提交事務 vs 依賴事務

  • CommittableTransaction:獨立事務根,可 Commit()/Rollback()。
  • DependentTransaction:依附現有事務 (根或另一依賴),**無 Commit**,僅 Complete() 通知完成;若未 Complete 父事務會阻塞或回滾。

DependentTransaction 兩大核心場景

場景一:跨執行緒流動事務 (非同步作業)

Transaction.Current 存於 TLS,新執行緒看不到。解法:主執行緒建立 DependentTransaction 傳給背景執行緒,背景執行緒設為 Transaction.Current。

private static void Transfer(string from, string to, double amount)
{
    var originalTx = Transaction.Current;
    var rootTx = new CommittableTransaction();
    try
    {
        Transaction.Current = rootTx;

        ThreadPool.QueueUserWorkItem(state =>
        {
            var depTx = state as DependentTransaction;
            Transaction.Current = depTx;
            try
            {
                Withdraw(from, amount);
                Deposit(to, amount);
                depTx.Complete(); // 通知父事務此分支完成
            }
            catch (Exception ex)
            {
                Transaction.Current.Rollback(ex);
            }
            finally
            {
                (depTx as IDisposable).Dispose();
                Transaction.Current = null;
            }
        }, rootTx.DependentClone(DependentCloneOption.BlockCommitUntilComplete));
        // BlockCommitUntilComplete:Commit 時等待所有 DependentTransaction.Complete()

        // 其他同步作業...
        rootTx.Commit();
    }
    catch (TransactionAbortedException ex)
    {
        rootTx.Rollback(ex);
    }
    finally
    {
        Transaction.Current = originalTx;
        rootTx.Dispose();
    }
}

DependentCloneOption 選擇指南

選項行為適用場景
BlockCommitUntilComplete父事務 Commit 阻塞,等待 Complete 或逾時**非同步分支**,必須確保完成才算數
RollbackIfNotComplete父事務 Commit 時若分支未 Complete → 直接回滾拋出**同步輔助作業**,失敗即整體失敗

場景二:實現「事務型方法」 (Transactional Methods)

目標:方法**有事務則加入,無事務則自建**。

static void InvokeInTransaction(Action action)
{
    var originalTx = Transaction.Current;
    CommittableTransaction rootTx = null;
    DependentTransaction depTx = null;

    if (Transaction.Current == null)
    {
        rootTx = new CommittableTransaction();
        Transaction.Current = rootTx;
    }
    else
    {
        depTx = Transaction.Current.DependentClone(DependentCloneOption.RollbackIfNotComplete);
        Transaction.Current = depTx;
    }

    try
    {
        action(); // 執行業務邏輯
        if (rootTx != null) rootTx.Commit();
        if (depTx != null) depTx.Complete();
    }
    catch (Exception ex)
    {
        Transaction.Current.Rollback(ex);
        throw;
    }
    finally
    {
        var tx = Transaction.Current;
        Transaction.Current = originalTx;
        tx.Dispose();
    }
}

// 使用:Withdraw/Deposit 變成事務型方法
static void Withdraw(string id, double amt) => InvokeInTransaction(() => Db.Execute("P_WITHDRAW", id, amt));
static void Deposit(string id, double amt) => InvokeInTransaction(() => Db.Execute("P_DEPOSIT", id, amt));

TransactionScope:事務編程的「瑞士刀」

上述 InvokeInTransaction 正是 TransactionScope 內部邏輯的簡化版。**實務上 95% 場景直接用 TransactionScope**。

基本用法

using (var scope = new TransactionScope())
{
    Withdraw("A", 100);
    Deposit("B", 100);
    scope.Complete(); // 標記成功,Dispose 時 Commit
} // Dispose 時自動 Commit/Rollback、還原 Transaction.Current

建構函數參數深度解析

參數型別說明
scopeOptionTransactionScopeOption環境事務存在時的行為 (Required/RequiresNew/Suppress)
scopeTimeoutTimeSpan事務逾時 (預設 1 分鐘)
transactionOptionsTransactionOptionsIsolationLevel + Timeout 組合
interopOptionEnterpriseServicesInteropOption與 COM+ 事務互操作模式

TransactionScopeOption 三種模式對比

模式行為典型用途
Required (預設)有事務則加入 (建立 DependentTx),無則建新 (CommittableTx)一般業務邏輯
RequiresNew**永遠建立新 CommittableTx**,與外部事務無關獨立日誌寫入、審計追蹤、補償操作
Suppress**暫時移除環境事務** (Transaction.Current = null),無事務控制非關鍵通知發送、快取刷新、唯讀查詢

隔離級別陷阱:巢狀 Required 必須一致

using (var outer = new TransactionScope()) // 預設 IsolationLevel.Serializable
{
    var opts = new TransactionOptions { IsolationLevel = IsolationLevel.ReadCommitted };
    using (var inner = new TransactionScope(TransactionScopeOption.Required, opts))
    {
        // ArgumentException: 衝突的隔離級別
    }
}

規則:Required 內層指定的 IsolationLevel **必須等於** 外層實際級別。建議:最外層統一指定,內層不再覆寫。

EnterpriseServicesInteropOption:COM+ 互操作

選項行為
None不同步 COM+ Context 與 System.Transactions
Automatic偵測現有 COM+ Context 並同步 (較常用)
Full強制雙向同步,效能損耗大 (可能建立新 COM+ Context)

Complete() 與 Dispose() 生命週期

  • Complete() 只是設定內部旗標 _complete = true,**不立即 Commit**。
  • Dispose() 時:_complete 為 true → Commit() (或 DependentTx.Complete());false → Rollback()。
  • Complete() 後至 Dispose() 前,**無法存取 Transaction.Current** (拋 InvalidOperationException)。

最佳實踐總結

  1. 預設用 TransactionScope,簡潔、正確、可巢狀。
  2. 跨執行緒非同步 才手動用 DependentClone(BlockCommitUntilComplete)。
  3. 獨立子事務 (日誌、審計) 用 TransactionScopeOption.RequiresNew。
  4. 非關鍵/唯讀 用 Suppress 避免不必要鎖爭用。
  5. 隔離級別 在最外層 Scope 統一設定,內層 Required 不再覆寫。
  6. 異常處理:勿捕捉 TransactionAbortedException 後繼續用同事務;讓它向上傳播觸發 Rollback。
  7. 資源管理員 (自訂非受控資源) 繼承 TransactionalOperation 實作 OnCommit/OnAbort。

結語

System.Transactions 提供了統一、可組合的事務抽象:CommittableTransaction 為根,DependentTransaction 為分支,TransactionScope 為語法糖。掌握三者關係與選項語意,即可在分散式系統中自信處理 ACID 事務,避免手動鎖管理的地獄。

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