Share via


將資源登記成為交易中的參與者

參與交易的每項資源都會受到資源管理員的管理,而這些資源管理員在採取行動時必須經過交易管理員的協調。訂閱者透過交易管理員登記到交易中,並收到告知來完成整個協調程序。

本主題將涵蓋如何在交易中登記資源 (或多項資源),以及登記的型別有哪些。在單一階段和多重階段中認可交易主題涵蓋如何在登記的資源中協調交易認可。

將資源登記到交易中

為了讓資源參與交易,資源必須登記到交易中。Transaction 類別會定義一組提供這個功能的方法,其名稱開頭為 Enlist。不同的 Enlist 方法會對應至資源管理員可能具有之不同型別的登記。具體來說,您可以使用變動性資源的 EnlistVolatile 方法,以及永久性資源的 EnlistDurable 方法。資源管理員的永久性 (反之為變動性) 指的是資源管理員是否支援故障復原。如果資源管理員支援故障復原,會在第一階段 (準備階段) 將資料保存在永久性儲存裝置中。這樣一來,如果資源管理員故障,資料就可以在復原後重新登記到交易中,並依據接收自 TM 的告知執行適當的動作。一般來說,變動性資源管理員會將變動性資源當成記憶體中的資料結構來管理 (例如,記憶體中的交易雜湊表),而永久性資源管理員則會管理具有較持久之備份存放區的資源 (例如,使用磁碟做為備份存放區的資料庫)。

在依據資源永久性支援來決定是否採用 EnlistDurableEnlistVolatile 方法之後,為了方便作業,您應該實作資源管理員的 IEnlistmentNotification 介面,以便登記資源並讓其參與兩階段交易認可 (2PC)。如需 2PC 的詳細資訊,請參閱在單一階段和多重階段中認可交易

單一參與者可藉由呼叫 EnlistDurableEnlistVolatile 數次為一個以上的這類通訊協定進行登記。

永久性登記

您可以使用 EnlistDurable 方法來登記資源管理員,以便以永久性資源身分參與交易。如果永久性資源管理員在交易中途停機,預期它會重新登記 (使用 Reenlist 方法) 到所有已參與但未完成第二階段的交易中,並於重新上線後執行復原。一旦完成復原程序,資源管理員便會呼叫 RecoveryComplete。如需復原的詳細資訊,請參閱執行復原

所有 EnlistDurable 方法都會將 Guid 物件當成第一個參數。交易管理員會使用 Guid,將永久性登記與特定的資源管理員關聯在一起。這麼一來,資源管理員在重新啟動時就必須持續使用相同的 Guid 來辨識自己 (即使是在不同的資源管理員之間亦然),否則復原會失敗。

EnlistDurable 方法的第二個參數會參考某個資源管理員實作以接收交易告知的物件。您會使用多載來告知交易管理員有關資源管理員是否支援單一階段交易認可 (SPC) 最佳化。在大部分情況下,您應該實作 IEnlistmentNotification 介面來參與兩階段交易認可 (2PC)。但是,如果您希望最佳化交易認可處理序,則可以考慮實作 SPC 的 ISinglePhaseNotification 介面。如需 SPC 的詳細資訊,請參閱在單一階段和多重階段中認可交易使用單一階段交易認可和可提升單一階段告知進行最佳化

第三個參數是一種 EnlistmentOptions 列舉型別,其值可為 NoneEnlistDuringPrepareRequired。如果將值設為 EnlistDuringPrepareRequired,登記作業可能會在收到來自交易管理員的準備告知時登記額外的資源管理員。但是,您應該瞭解這種登記型別不適用於單一階段交易認可最佳化作業。

變動性登記

管理快取之類的變動性資源的參與者,應該使用 EnlistVolatile 方法來登記。此類物件也許無法取得交易結果,或是在系統故障後復原所參與的任何交易狀態。

如同先前所述,如果資源管理員負責管理記憶體中的變動性資源,就需要進行變動性登記作業。使用 EnlistVolatile 的其中一項好處就是,它不會強制擴大不必要的交易規模。如需交易擴大規模的詳細資訊,請參閱交易管理擴大規模主題。登記變動性資源同時意指交易管理員處理交易的方式,以及交易管理員對資源管理員的期待等各項差異。這是因為變動性資源管理員無法執行復原。EnlistVolatile 方法不會使用 Guid 參數,因為變動性資源管理員無法執行復原,也無法呼叫需要 GuidReenlist 方法。

有關永久性登記方面,不管您使用哪種多載方法來登記,都會向交易管理員表示您的資源管理員是否支援單一階段交易認可最佳化。由於變動性資源管理員無法執行復原,因此準備階段期間不會針對變動性登記寫入復原資訊。如此一來,呼叫 RecoveryInformation 方法將產生 InvalidOperationException 的結果。

下列範例會顯示如何使用 EnlistVolatile 方法將此類物件登記為交易中的參與者。

    Public Shared Sub Main()
        Try
            Using scope As TransactionScope = New TransactionScope()

                'Create an enlistment object
                Dim myEnlistmentClass As New EnlistmentClass

                'Enlist on the current transaction with the enlistment object
                Transaction.Current.EnlistVolatile(myEnlistmentClass, EnlistmentOptions.None)

                'Perform transactional work here.

                'Call complete on the TransactionScope based on console input
                Dim c As ConsoleKeyInfo
                While (True)
                    Console.Write("Complete the transaction scope? [Y|N] ")
                    c = Console.ReadKey()
                    Console.WriteLine()
                    If (c.KeyChar = "Y") Or (c.KeyChar = "y") Then
                        scope.Complete()
                        Exit While
                    ElseIf ((c.KeyChar = "N") Or (c.KeyChar = "n")) Then
                        Exit While
                    End If
                End While
            End Using
        Catch ex As TransactionException
            Console.WriteLine(ex)
        Catch
            Console.WriteLine("Cannot complete transaction")
            Throw
        End Try
    End Sub
End Class

Public Class EnlistmentClass
    Implements IEnlistmentNotification

    Public Sub Prepare(ByVal myPreparingEnlistment As PreparingEnlistment) Implements System.Transactions.IEnlistmentNotification.Prepare
        Console.WriteLine("Prepare notification received")

        'Perform transactional work

        'If work finished correctly, reply with prepared
        myPreparingEnlistment.Prepared()
    End Sub

    Public Sub Commit(ByVal myEnlistment As Enlistment) Implements System.Transactions.IEnlistmentNotification.Commit
        Console.WriteLine("Commit notification received")

        'Do any work necessary when commit notification is received

        'Declare done on the enlistment
        myEnlistment.Done()
    End Sub

    Public Sub Rollback(ByVal myEnlistment As Enlistment) Implements System.Transactions.IEnlistmentNotification.Rollback
        Console.WriteLine("Rollback notification received")

        'Do any work necessary when rollback notification is received

        'Declare done on the enlistment
        myEnlistment.Done()
    End Sub

    Public Sub InDoubt(ByVal myEnlistment As Enlistment) Implements System.Transactions.IEnlistmentNotification.InDoubt
        Console.WriteLine("In doubt notification received")

        'Do any work necessary when indout notification is received

        'Declare done on the enlistment
        myEnlistment.Done()
    End Sub
End Class
static void Main(string[] args)
{
    try
    {
        using (TransactionScope scope = new TransactionScope())
        {
        
            //Create an enlistment object
            myEnlistmentClass myElistment = new myEnlistmentClass();

            //Enlist on the current transaction with the enlistment object
            Transaction.Current.EnlistVolatile(myElistment, EnlistmentOptions.None);

            //Perform transactional work here.

            //Call complete on the TransactionScope based on console input
                            ConsoleKeyInfo c;
            while(true)
                            {
                Console.Write("Complete the transaction scope? [Y|N] ");
                c = Console.ReadKey();
                Console.WriteLine();
        
                                    if ((c.KeyChar == 'Y') || (c.KeyChar == 'y'))
                {
                    scope.Complete();
                    break;
                }
                else if ((c.KeyChar == 'N') || (c.KeyChar == 'n'))
                {
                    break;
                }
            }
        }
    }
    catch (System.Transactions.TransactionException ex)
    {
        Console.WriteLine(ex);
    }
    catch
    {
        Console.WriteLine("Cannot complete transaction");
        throw;
    }
}

class myEnlistmentClass : IEnlistmentNotification
{
    public void Prepare(PreparingEnlistment preparingEnlistment)
    {
        Console.WriteLine("Prepare notification received");

        //Perform transactional work

        //If work finished correctly, reply prepared
        preparingEnlistment.Prepared();

        // otherwise, do a ForceRollback
        preparingEnlistment.ForceRollback();
    }

    public void Commit(Enlistment enlistment)
    {
        Console.WriteLine("Commit notification received");

        //Do any work necessary when commit notification is received

        //Declare done on the enlistment
        enlistment.Done();
    }

    public void Rollback(Enlistment enlistment)
    {
        Console.WriteLine("Rollback notification received");

        //Do any work necessary when rollback notification is received

        //Declare done on the enlistment
        enlistment.Done();
    }

    public void InDoubt(Enlistment enlistment)
    {
        Console.WriteLine("In doubt notification received");

        //Do any work necessary when indout notification is received
        
        //Declare done on the enlistment
        enlistment.Done();
    }
}

最佳化效能

Transaction 類別也會提供 EnlistPromotableSinglePhase 方法,以便登記可提升單一階段登記 (PSPE)。這樣一來永久性資源管理員 (RM) 就可以裝載並「擁有」交易,並可在稍後視需要將規模擴大為由 MSDTC 管理。如需詳細資訊,請參閱使用單一階段交易認可和可提升單一階段告知進行最佳化

請參閱

概念

使用單一階段交易認可和可提升單一階段告知進行最佳化
在單一階段和多重階段中認可交易

Footer image

Copyright © 2007 by Microsoft Corporation. All rights reserved.