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

C# 資料庫交易 (Transaction) 原理與實戰完整指南

     編輯:關於C#

資料庫交易是確保資料一致性的核心機制。本文從 ACID 理論出發,深入解析 ADO.NET 中 SqlTransaction 的操作模式、隔離等級、儲存點、巢狀交易限制與效能考量,提供完整 C# 實戰範例。

什麼是資料庫交易?

交易將一組相關資料庫操作視為單一邏輯工作單元:要麼全部成功,要麼全部失敗。典型情境:網購付款流程需同時扣庫存、記付款、建訂單、更新會員資訊,任一步驟失敗需全部復原。

ACID 四大特性

特性說明ADO.NET 對應機制
原子性 Atomicity所有操作視為不可分割整體,全做或全不做SqlTransaction.Commit() / Rollback()
一致性 Consistency交易完成前後資料庫皆滿足所有完整性條件約束資料庫引擎強制執行 (FK, CK, Trigger 等)
隔離性 Isolation並行交易互不干擾,避免髒讀、不可重複讀、幻讀IsolationLevel 列舉設定
持久性 Durability交易提交後異動永久保存,不因系統故障遺失資料庫 WAL (Write-Ahead Logging) 機制

ADO.NET 交易核心類別

  • SqlConnection.BeginTransaction():啟動交易,回傳 SqlTransaction 物件。
  • SqlCommand.Transaction:將命令關聯至交易。
  • SqlTransaction.Commit():提交交易。
  • SqlTransaction.Rollback():回滾交易 (可指定儲存點)。
  • SqlTransaction.Save(string savePoint):建立儲存點。

基本交易範本


using (SqlConnection conn = new SqlConnection(connStr))
{
    conn.Open();
    SqlTransaction tran = conn.BeginTransaction(); // 或指定 IsolationLevel
    SqlCommand cmd = conn.CreateCommand();
    cmd.Transaction = tran;

    try
    {
        cmd.CommandText = "UPDATE Accounts SET Balance -= 100 WHERE Id = 1";
        cmd.ExecuteNonQuery();
        
        cmd.CommandText = "UPDATE Accounts SET Balance += 100 WHERE Id = 2";
        cmd.ExecuteNonQuery();
        
        tran.Commit();
    }
    catch (Exception ex)
    {
        tran.Rollback();
        // 記錄錯誤、拋出或處理
        throw;
    }
}

不可在交易中執行的 SQL 指令

以下 DDL/管理指令會導致例外:
CREATE/ALTER/DROP DATABASE, BACKUP/RESTORE, DISK INIT, RECONFIGURE, UPDATE STATISTICS, LOAD DATABASE 等。
原則:交易僅適用於 DML (SELECT/INSERT/UPDATE/DELETE) 及部分 DDL (如 CREATE TABLE 在某些版本受限)。

儲存點:部分回滾機制


tran.Save("BeforeRiskyUpdate");
cmd.CommandText = "UPDATE HighRiskTable SET ...";
try { cmd.ExecuteNonQuery(); }
catch { tran.Rollback("BeforeRiskyUpdate"); /* 僅回滾到此點,前面更新保留 */ }

適用情境:驗證成本極高、失敗機率極低的作業,避免事前檢查的效能損耗。

隔離等級完整對照

IsolationLevel髒讀不可重複讀幻讀並發度適用場景
ReadUncommitted✅✅✅最高近似報表、可容忍髒資料
ReadCommitted (預設)❌✅✅高大多數 OLTP 系統
RepeatableRead❌❌✅中需穩定讀取同一資料集
Serializable❌❌❌最低嚴格財務對帳、庫存扣款
Snapshot❌❌❌高 (行版本)高並發且需一致性快照,需資料庫啟用 ALLOW_SNAPSHOT_ISOLATION

設定方式:conn.BeginTransaction(IsolationLevel.Serializable)。注意:交易執行中途變更隔離等級立即生效,後續指令採用新等級。

分散式交易 (System.Transactions)

跨多個資料庫/資源管理員需使用 TransactionScope (需 MSDTC 服務):


using (TransactionScope scope = new TransactionScope())
{
    using (SqlConnection conn1 = new SqlConnection(connStr1))
    using (SqlConnection conn2 = new SqlConnection(connStr2))
    {
        conn1.Open(); conn2.Open();
        // 多資料庫操作
        scope.Complete(); // 未呼叫則自動 Rollback
    }
}

效能與最佳實務

  • 縮短交易範圍:僅包含必要資料庫操作,避免在交易中進行網路呼叫、複雜運算、UI 互動。
  • 避免長交易:長交易持有鎖定久,導致封鎖、死鎖、交易記錄膨脹。
  • 正確釋放資源:using 區塊確保 Connection/Transaction/Command 正確 Dispose。
  • 死鎖處理:捕捉 SqlException (Number=1205) 實施重試邏輯 (指數退避)。
  • 非同步支援:.NET Core 3.0+ 支援 await conn.BeginTransactionAsync()、await tran.CommitAsync()。

常見錯誤與除錯技巧

掌握交易原理與 ADO.NET API 細節,能讓您建構出資料一致性可靠、效能優異的企業級應用系統。現代開發亦可考慮使用 TransactionScope 簡化程式碼,或配合 EF Core 的 DbContext.Database.BeginTransaction() 進行 ORM 層面的交易控制。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved
錯誤現象可能原因解決方向
SqlTransaction 建構函式無參數嘗試 new SqlTransaction()必須用 conn.BeginTransaction() 取得
交易未提交資料卻可見隔離等級 ReadUncommitted 或未提交讀調整隔離等級或確認交易已 Commit
Timeout expired鎖定等待過久、死鎖、索引缺失優化查詢、縮短交易、檢查索引、設定 CommandTimeout
分散式交易失敗MSDTC 未啟動、防火牆阻擋、網路不通服務啟動、防火牆開放 135/動態埠、測試 DTCPing