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

C# 資料庫事務核心原理與實戰應用(上)

     編輯:關於C語言

什麼是資料庫事務?

資料庫事務是指作為單一邏輯工作單元執行的一系列操作。想像一次網購交易,其付款流程至少包含以下資料庫操作:

  • 更新客戶購買商品的庫存資訊
  • 保存客戶付款資訊(可能涉及銀行系統互動)
  • 生成訂單並寫入資料庫
  • 更新用戶相關資料(如購買數量等)

正常情況下,這些操作將順利完成,交易成功,所有相關資料同步更新。但若任一環節出錯——例如更新庫存時異常、銀行帳戶餘額不足——交易將失敗。一旦失敗,資料庫必須保持交易前的狀態:庫存未更新、款項未扣款、訂單未生成。否則資料將陷入混亂不可預測的狀態。資料庫事務正是為了保證這類情況下交易的平穩性與可預測性而存在的技術。

事務的 ACID 四大特性

事務處理確保:除非事務單元內所有操作均成功完成,否則不會永久更新面向資料的資源。將一組相關操作組合為「要麼全成功、要麼全失敗」的單元,可簡化錯誤恢復並提升應用程式可靠性。一個邏輯工作單元要成為事務,必須滿足 ACID(原子性、一致性、隔離性、持久性)特性:

原子性

事務必須是原子工作單元;對其資料修改,要麼全執行,要麼全不執行。通常與某事務關聯的操作具有共同目標且相互依賴。若系統僅執行操作子集,可能破壞事務整體目標。原子性消除了系統處理操作子集的可能性。

一致性

事務完成時,必須使所有資料保持一致狀態。在相關資料庫中,所有規則必須應用於事務修改,以維護資料完整性。事務結束時,所有內部資料結構(如 B 樹索引、雙向鏈表)必須正確。部分維護一致性的責任在應用程式開發人員,他們必須確保應用程式強制所有已知的完整性約束。例如開發轉帳應用時,應避免在轉帳過程中任意移動小數點。

隔離性

並發事務所做的修改必須與其他並發事務的修改隔離。事務查看資料時的狀態,要麼是另一並發事務修改前的狀態,要麼是修改後的狀態,不會看到中間狀態。這稱為可串行性,因為能重新裝載起始資料並重播一系列事務,使資料結束狀態與原始事務執行狀態相同。最高隔離級別為可序列化,此級別下從一組可並行執行的事務獲得的結果與連續執行每個事務的結果相同。因高度隔離會限制並發事務數,某些應用會降低隔離級別以換取更大吞吐量。

持久性

事務完成後,其對系統的影響是永久性的。該修改即使出現致命系統故障也將一直保持。

DBMS 的責任與開發者的任務

企業級資料庫管理系統(DBMS)負責提供保證事務物理完整性的機制。以常用的 SQL Server 2000 為例,它具備鎖定機制隔離事務、記錄機制保證持久性等。因此,開發者無需關心事務的物理完整性,而應專注於:何時使用事務、事務對效能的影響、如何正確使用事務等。本文將探討在 .NET Framework 下使用 C# 操作資料庫事務的各個層面。

體驗 SQL 語言的事務機制

SQL Server 2000 作為大型企業級資料庫,對事務提供良好支援。可使用 SQL 陳述式定義、提交、回滾事務。下列 SQL 代碼定義一個名為 "MyTransaction" 的事務(限於篇幅,不討論 SQL 程式撰寫細節):

DECLARE @TranName VARCHAR(20)
SELECT @TranName = 'MyTransaction'
BEGIN TRANSACTION @TranName
USE pubs
UPDATE roysched
SET royalty = royalty * 1.10
WHERE title_id LIKE 'Pc%'
COMMIT TRANSACTION MyTransaction

此處使用 SQL Server 2000 內建範例資料庫 pubs,提交事務後將為所有暢銷電腦書支付的版稅增加 10%。在查詢分析器中選擇 pubs 資料庫執行即可見效。

在 C# 程式中執行 SQL 事務

在一般 SQL 查詢中,將查詢語句賦值給 SqlCommand.CommandText 屬性;此處同理,將上述 SQL 陳述式字串連接後賦給 CommandText 即可。注意:SQL 腳本中的 "GO" 陳述式標誌批次結束,在 C# 中執行時不需要。以下程式碼驗證此想法:

// TranSql.cs
using System;
using System.Data;
using System.Data.SqlClient;

namespace ASPcn
{
    public class DbTranSql
    {
        // 將事務放到 SQL Server 中執行
        public void DoTran()
        {
            // 建立連接並打開
            SqlConnection myConn = GetConn();
            myConn.Open();
            SqlCommand myComm = new SqlCommand();
            try
            {
                myComm.Connection = myConn;
                myComm.CommandText = "DECLARE @TranName VARCHAR(20) ";
                myComm.CommandText += "SELECT @TranName = 'MyTransaction' ";
                myComm.CommandText += "BEGIN TRANSACTION @TranName ";
                myComm.CommandText += "USE pubs ";
                myComm.CommandText += "UPDATE roysched SET royalty = royalty * 1.10 WHERE title_id LIKE 'Pc%' ";
                myComm.CommandText += "COMMIT TRANSACTION MyTransaction ";
                myComm.ExecuteNonQuery();
            }
            catch (Exception err)
            {
                throw new ApplicationException("事務操作出錯,系統信息:" + err.Message);
            }
            finally
            {
                myConn.Close();
            }
        }

        // 獲取資料連接
        private SqlConnection GetConn()
        {
            string strSql = "Data Source=localhost;Integrated Security=SSPI;user id=sa;passWord=";
            SqlConnection myConn = new SqlConnection(strSql);
            return myConn;
        }
    }

    public class Test
    {
        public static void Main()
        {
            DbTranSql tranTest = new DbTranSql();
            tranTest.DoTran();
            Console.WriteLine("事務處理已經成功完成。");
            Console.ReadLine();
        }
    }
}

注意 SqlCommand 對象 myComm 的 CommandText 屬性僅是前面 SQL 代碼字串連接,且移除了 "GO"。此語句如同一般查詢提交給 DBMS 處理,接收返回結果。程式輸出「事務處理已經成功完成」,再用企業管理器查看 pubs 資料庫 roysched 表,所有 title_id 以 "PC" 開頭書籍的 royalty 欄位值均增加 0.1 倍。

此處並未使用 ADO.NET 的事務處理機制,而是將執行事務的 SQL 當作一般查詢執行,因此該事務完全未用到 .NET 相關特性。

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