本機交易

當您想要將多個工作繫結在一起,使其以單一工作單位的形式執行時,將會使用 ADO.NET 中的交易。 例如,想像應用程式正在執行兩項工作。 首先,它會更新包含訂單資訊的資料表。 然後會更新包含存貨資訊的資料表,將訂購項目記入借方。 如果其中任何一項作業失敗,則兩個更新作業都會復原。

決定異動類型

當交易為單一階段交易,且直接由資料庫處理時,系統便會將該交易視為本機交易。 當交易由交易監視器進行協調,並使用保全機制 (如兩階段交易認可) 進行交易解析時,系統便會將該交易視為分散式交易。

每個 .NET Framework 資料提供者都有自己的 Transaction 物件來執行本機交易。 如果您需要在 SQL Server 資料庫中執行異動,請選擇 System.Data.SqlClient 異動。 若為 Oracle 異動,請使用 System.Data.OracleClient 提供者。 此外,還有一個 DbTransaction 類別可用於撰寫獨立於提供者以外且需要交易的程式碼。

注意

交易在伺服器上執行時效率最高。 如果您使用的 SQL Server 資料庫大量使用明確的異動,請考慮使用 Transact-SQL BEGIN TRANSACTION 陳述式,將它們寫入為預存程序。

使用單一連接執行異動

在 ADO.NET 中,您可以使用 Connection 物件控制交易。 您可使用 BeginTransaction 方法來起始本機異動。 開始異動之後,您可使用 Transaction 物件的 Command 屬性,在該異動中登記命令。 然後,您可根據異動元件的成敗,來認可或復原對資料來源所做的修改。

注意

EnlistDistributedTransaction 方法不可用於本機異動。

交易的範圍僅限於連接。 下列範例執行由 try 區塊中的兩個單獨命令所組成的明確異動。 這些命令會針對 AdventureWorks SQL Server 範例資料庫的 Production.ScrapReason 資料表執行 INSERT 陳述式,如果未擲回例外狀況,該陳述式便會得到認可。 如果擲回例外狀況,catch 區塊中的程式碼便會復原交易。 如果異動在完成之前遭到中止或連接關閉,則會自動復原該異動。

範例

請遵循下列步驟來執行異動。

  1. 呼叫 BeginTransaction 物件的 SqlConnection 方法,來標記交易的開始。 BeginTransaction 方法會將參考傳回給交易。 此參考會指派給登記在交易中的 SqlCommand 物件。

  2. Transaction 物件指派給要執行之 TransactionSqlCommand 屬性。 如果在有異動正在作用中的連接上執行命令,且 Transaction 物件尚未指派給 Transaction 物件的 Command 屬性,便會擲回例外狀況。

  3. 執行必要的命令。

  4. 呼叫 Commit 物件的 SqlTransaction 方法來完成交易,或呼叫 Rollback 方法來中止交易。 如果在執行 CommitRollback 方法之前關閉或處置連接,則會復原異動。

下列程式碼範例藉由搭配使用 ADO.NET 與 Microsoft SQL Server 來示範異動邏輯。

using (SqlConnection connection = new(connectionString))
{
    connection.Open();

    // Start a local transaction.
    SqlTransaction sqlTran = connection.BeginTransaction();

    // Enlist a command in the current transaction.
    SqlCommand command = connection.CreateCommand();
    command.Transaction = sqlTran;

    try
    {
        // Execute two separate commands.
        command.CommandText =
          "INSERT INTO Production.ScrapReason(Name) VALUES('Wrong size')";
        command.ExecuteNonQuery();
        command.CommandText =
          "INSERT INTO Production.ScrapReason(Name) VALUES('Wrong color')";
        command.ExecuteNonQuery();

        // Commit the transaction.
        sqlTran.Commit();
        Console.WriteLine("Both records were written to database.");
    }
    catch (Exception ex)
    {
        // Handle the exception if the transaction fails to commit.
        Console.WriteLine(ex.Message);

        try
        {
            // Attempt to roll back the transaction.
            sqlTran.Rollback();
        }
        catch (Exception exRollback)
        {
            // Throws an InvalidOperationException if the connection
            // is closed or the transaction has already been rolled
            // back on the server.
            Console.WriteLine(exRollback.Message);
        }
    }
}
Using connection As New SqlConnection(connectionString)
    connection.Open()

    ' Start a local transaction.
    Dim sqlTran As SqlTransaction = connection.BeginTransaction()

    ' Enlist a command in the current transaction.
    Dim command As SqlCommand = connection.CreateCommand()
    command.Transaction = sqlTran

    Try
        ' Execute two separate commands.
        command.CommandText = _
          "INSERT INTO Production.ScrapReason(Name) VALUES('Wrong size')"
        command.ExecuteNonQuery()
        command.CommandText = _
          "INSERT INTO Production.ScrapReason(Name) VALUES('Wrong color')"
        command.ExecuteNonQuery()

        ' Commit the transaction
        sqlTran.Commit()
        Console.WriteLine("Both records were written to database.")

    Catch ex As Exception
        ' Handle the exception if the transaction fails to commit.
        Console.WriteLine(ex.Message)

        Try
            ' Attempt to roll back the transaction.
            sqlTran.Rollback()

        Catch exRollback As Exception
            ' Throws an InvalidOperationException if the connection 
            ' is closed or the transaction has already been rolled 
            ' back on the server.
            Console.WriteLine(exRollback.Message)
        End Try
    End Try
End Using

另請參閱