SqlTransaction 資料庫事務

事務(Transaction):一組SQL操作採用原子執行,要麼全部成功提交(Commit),要麼全部失敗回滾(Rollback),符合ACID特性。
在.NET Framework/.NET 當中透過 SqlTransaction(僅適用SQL Server)來實作。

流程重點:

  1. 開啟資料庫連線 conn.Open()
  2. 透過連線建立事務 conn.BeginTransaction()
  3. 將事務物件指派給 SqlCommand.Transaction
  4. 批次執行多筆SQL敘述
  5. 無例外:tx.Commit();捕捉例外:tx.Rollback()

範例

原始程式碼缺少catch回滾處理邏輯,這裡提供完整可執行版本

public static int ExecuteSqlTran(List<string> SQLStringList)
{
    using (SqlConnection conn = new SqlConnection(connectionString))
    {
        conn.Open();
        SqlCommand cmd = new SqlCommand();
        cmd.Connection = conn;
        SqlTransaction tx = conn.BeginTransaction();
        cmd.Transaction = tx;
        try
        {
            int count = 0;
            for (int n = 0; n < SQLStringList.Count; n++)
            {
                string strsql = SQLStringList[n];
                if (strsql.Trim().Length > 1)
                {
                    cmd.CommandText = strsql;
                    count += cmd.ExecuteNonQuery();
                }
            }
            tx.Commit(); // 全部執行成功,提交事務
            return count;
        }
        catch (Exception ex)
        {
            tx.Rollback(); // 任一指令出錯,全部回滾
            throw ex; // 向外拋出例外,讓上層知道執行失敗
        }
    }
}Code language: C# (cs)

此版本直接拼接SQL字串,存在SQL注入風險,適合拿來理解事務原理;正式專案務必優先使用參數化查詢

加入參數化的事務範例

迴圈寫入資料,透過SqlParameter防範注入,幾個關鍵注意點:

  1. 每次迴圈結束呼叫 sqlCom.Parameters.Clear() 清除舊參數,避免參數累積導致報錯
  2. 重複使用同一個SqlCommand物件,只更新CommandText與參數內容
SqlCommand sqlCom = new SqlCommand();
sqlCom.Connection = conn;
SqlTransaction st = conn.BeginTransaction();
sqlCom.Transaction = st;
int res = 0;
try
{
    for (int i = 0; i < 10; i++)
    {
        sqlCom.CommandText = "INSERT INTO [dbo].[Article]([Title])VALUES(@Title)";
        SqlParameter param = new SqlParameter("@Title", SqlDbType.NVarChar, 250);
        param.Value = i + "這是新的標題" + DateTime.Now;
        sqlCom.Parameters.Add(param);
        res += sqlCom.ExecuteNonQuery();
        sqlCom.Parameters.Clear(); // 清空參數,供下一輪使用
    }
    st.Commit();
}
catch (Exception)
{
    st.Rollback(); // 發生例外,全部復原
}Code language: C# (cs)

1. 一定要遵守的強制規則

  • BeginTransaction() 必須在連線Open之後才呼叫
  • SqlCommand 一定要設定 Transaction 屬性,否則會拋出例外
  • 呼叫完 Commit() / Rollback() 事務就自動結束,不可重複呼叫

其他備註

  • .NET Core/.NET 5+ 建議使用 using 自動釋放 SqlTransaction
  • 處理大量SQL批次場景,可以考慮 SqlBulkCopy,效能比迴圈呼叫ExecuteNonQuery更好
  • 跨資料庫的事務需求,SqlTransaction無法支援,要改用分散式事務(TransactionScope

SqlTransaction 資料庫事務

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *