トランザクションの参加要素としてのリソースの参加Enlisting Resources as Participants in a Transaction

トランザクションに参加する各リソースは、リソース マネージャーによって管理され、その動作はトランザクション マネージャーによって調整されます。Each resource participating in a transaction is managed by a resource manager, whose actions are coordinated by a transaction manager. この調整は、トランザクション マネージャーを介してトランザクションに参加したサブスクライバーへの通知によって行われます。The coordination is done through notifications given to subscribers who have enlisted in a transaction through the transaction manager.

ここでは、単一または複数のリソースがトランザクションに参加する方法と、さまざまな種類の参加について説明します。This topic covers how a resource (or multiple resources) can be enlisted in a transaction, as well as the different types of enlistment. 単一フェーズおよびマルチフェーズでのトランザクションのコミット」では、参加しているリソース間でトランザクションコミットメントを調整する方法について説明します。The Committing a Transaction in Single-Phase and Multi-Phase topic covers how transaction commitment can be coordinated among enlisted resources.

トランザクションへのリソースの参加Enlisting Resources in a Transaction

リソースをトランザクションに参加させるには、リソースをトランザクションに登録する必要があります。In order for a resource to participate in a transaction, it must enlist in the transaction. クラスTransactionは、この機能を提供する、登録で始まる名前を持つ一連のメソッドを定義します。The Transaction class defines a set of methods whose names begin with Enlist that provide this functionality. さまざまな参加メソッドは、リソースマネージャーが持つことのできるさまざまな種類の参加リストに対応します。The different Enlist methods correspond to the different types of enlistment that a resource manager may have. 具体的には、揮発性リソースには EnlistVolatile メソッド、永続性リソースには EnlistDurable メソッドを使用します。Specifically, you use the EnlistVolatile methods for volatile resources, and the EnlistDurable method for durable resources. リソース マネージャーの永続性または揮発性とは、リソース マネージャーがエラーの回復をサポートするかどうかを意味します。The durability (or conversely the volatility) of a resource manager refers to whether the resource manager supports failure recovery. リソース マネージャーがエラーの回復をサポートする場合、フェーズ 1 (準備) 中にデータが永続ストレージに保存されます。したがって、リソース マネージャーがダウンした場合でも、回復時にトランザクションへの再参加を行い、TM から受信した通知に基づいて適切な動作を実行できます。If a resource manager supports failure recovery, it persists data to durable storage during Phase1 (prepare) such that if the resource manager goes down, it can re-enlist in the transaction upon recovery and perform the proper actions based on the notifications received from the TM. 一般に、揮発性リソース マネージャーは、メモリ内のデータ構造 (たとえば、メモリ内のトランザクション ハッシュ テーブル) などの揮発性リソースを管理し、永続的リソース マネージャーは、より永続的なバッキング ストアを持つリソース (たとえば、バッキング ストアがディスクであるデータベース) を管理します。In general, volatile resource managers manage volatile resources such as an in-memory data structure (for example, an in-memory transacted-hashtable), and durable resource managers manage resources that have a more persistent backing store (for example, a database whose backing store is disk).

簡単に説明すると、リソースが永続性をサポートするかどうかに応じて、EnlistDurable メソッドまたは EnlistVolatile メソッドのどちらを使用するかを決定した後、リソース マネージャーに IEnlistmentNotification インターフェイスを実装して、2 フェーズ コミット (2PC) に参加するようにリソースを登録する必要があります。For simplicity, after deciding whether to use the EnlistDurable or EnlistVolatile method based on your resource's durability support, you should enlist your resource to participate in Two Phase Commit (2PC) by implementing the IEnlistmentNotification interface for your resource manager. 2PC の詳細については、「単一フェーズおよび複数フェーズでのトランザクションのコミット」を参照してください。For more information on 2PC, see Committing a Transaction in Single-Phase and Multi-Phase.

EnlistDurable および EnlistVolatile を複数回呼び出すことにより、これらのプロトコルのうち、複数のプロトコルに単一の参加要素を参加させることができます。A single participant can enlist for more than one of these protocols by calling EnlistDurable and EnlistVolatile multiple times.

永続的参加リストDurable Enlistment

EnlistDurable メソッドは、リソース マネージャーを永続性リソースとしてトランザクションに参加させるために使用します。The EnlistDurable methods are used to enlist a resource manager for participation in the transaction as a durable resource. 永続的リソース マネージャーがトランザクション中にダウンした場合、リソース マネージャーはオンラインに戻った後、フェーズ 2 が完了していない参加要素を Reenlist メソッドを使用してすべてのトランザクションに再参加させ、回復を実行します。回復プロセスが完了したら、RecoveryComplete を呼び出します。It is expected that if a durable resource manager is brought down in the middle of a transaction, it can perform recovery once it is brought back online by reenlisting (using the Reenlist method) in all transactions in which it was a participant and did not complete phase 2, and call RecoveryComplete once it finishes recovery processing. 回復の詳細については、「回復の実行」を参照してください。For more information on recovery, see Performing Recovery.

すべての EnlistDurable メソッドは、最初のパラメーターとして Guid オブジェクトを使用します。The EnlistDurable methods all take a Guid object as their first parameter. トランザクション マネージャーは、この Guid を使用して、永続参加リストと特定のリソース マネージャーを関連付けます。The Guid is used by the transaction manager to associate a durable enlistment with a particular resource manager. そのため、リソース マネージャーが再起動時に自身を他のリソース マネージャーと識別できるように、一貫して同じ Guid を使用することが不可欠です。そうでない場合、回復が失敗する可能性があります。As such, it is imperative that a resource manager consistently uses the same Guid to identify itself even across different resource managers upon restarting, otherwise the recovery can fail.

EnlistDurable メソッドの第 2 パラメーターは、トランザクション通知を受信するためにリソース マネージャーが実装するオブジェクトへの参照です。The second parameter of the EnlistDurable method is a reference to the object that the resource manager implements to receive transaction notifications. 使用するオーバーロードにより、リソース マネージャーが単一フェーズ コミット (SPC) の最適化をサポートするかどうかがトランザクション マネージャーに通知されます。The overload you use informs the transaction manager whether your resource manager supports the Single Phase Commit (SPC) optimization. ほとんどの場合、2 フェーズ コミット (2PC) に参加するために IEnlistmentNotification インターフェイスを実装します。Most of the time you would implement the IEnlistmentNotification interface to take part in Two-Phase Commit (2PC). ただし、コミット プロセスを最適化する場合は、SPC 用の ISinglePhaseNotification インターフェイスの実装を検討することもできます。However, if you want to optimize the commit process, you can consider implementing the ISinglePhaseNotification interface for SPC. SPC の詳細については、単一フェーズコミットと昇格可能単一フェーズ通知を使用した単一フェーズおよびマルチフェーズおよび最適化でのトランザクションのコミットに関する説明を参照してください。For more information on SPC, see Committing a Transaction in Single-Phase and Multi-Phase and Optimization using Single Phase Commit and Promotable Single Phase Notification.

第 3 パラメーターは EnlistmentOptions 列挙体であり、その値は None または EnlistDuringPrepareRequired のいずれかです。The third parameter is an EnlistmentOptions enumeration, whose value can be either None or EnlistDuringPrepareRequired. この値が EnlistDuringPrepareRequired に設定されている場合、トランザクション マネージャーから Prepare 通知を受信したときに、参加リストが追加リソース マネージャーを参加させる可能性があります。If the value is set to EnlistDuringPrepareRequired, the enlistment may enlist additional resource managers upon receiving the Prepare notification from the transaction manager. ただし、この種類の参加リストは単一フェーズ コミットの最適化の条件を満たさないことに注意してください。However, you should be aware that this type of enlistment is not eligible for the Single Phase Commit optimization.

揮発性参加リストVolatile Enlistment

キャッシュなどの揮発性リソースを管理する参加要素は、EnlistVolatile メソッドを使用して参加させる必要があります。Participants managing volatile resources such as a cache should enlist using the EnlistVolatile methods. このようなオブジェクトは、トランザクションの結果を取得したり、システム障害の後で、参加しているトランザクションの状態を回復したりできない場合があります。Such objects might not be able to obtain the outcome of a transaction or recover the state of any transaction they participate in after a system failure.

前に述べたように、リソース マネージャーはメモリ内の揮発性リソースを管理する場合、揮発性参加リストを作成します。As stated previously, a resource manager would make a volatile enlistment if it manages an in-memory, volatile resource. EnlistVolatile を使用する利点の 1 つに、トランザクションの不要なエスカレーションを強制しないことがあります。One of the benefits of using EnlistVolatile is that it does not force an unnecessary escalation of the transaction. トランザクションのエスカレーションの詳細については、「トランザクション管理のエスカレーション」を参照してください。For more information on transaction escalation, see Transaction Management Escalation topic. 揮発性のデータを参加させると、トランザクションマネージャーによって参加が処理される方法と、トランザクションマネージャーによってリソースマネージャーに期待されることが異なります。Enlisting volatility implies both a difference in how the enlistment is handled by the transaction manager, as well as what is expected of the resource manager by the transaction manager. これは、揮発性リソース マネージャーが回復を実行しないためです。This is because a volatile resource manager does not perform recovery. 揮発性リソース マネージャーが回復を実行せず、EnlistVolatile を必要とする Guid メソッドを呼び出さないため、Reenlist メソッドは Guid パラメーターを取得しません。The EnlistVolatile methods do not take a Guid parameter, because a volatile resource manager does not perform recovery and would not call the Reenlist method which needs a Guid.

永続的参加リストの場合と同様に、どのオーバーロード メソッドを使用して参加する場合でも、リソース マネージャーが単一フェーズ コミットの最適化をサポートするかどうかがトランザクション マネージャーに示されます。As with durable enlistments, whichever overload method you use to enlist denotes to the transaction manager whether your resource manager supports the Single Phase Commit optimization. 揮発性リソース マネージャーが回復を実行できないため、準備フェーズ中、回復情報は揮発性参加リストに書き込まれません。Since a volatile resource manager cannot perform recovery, no recovery information is written for a volatile enlistment during the Prepare phase. したがって、RecoveryInformation メソッドを呼び出すと、InvalidOperationException になります。Therefore, calling the RecoveryInformation method results in an InvalidOperationException.

次の例は、EnlistVolatile メソッドを使用して、このようなオブジェクトを参加要素としてトランザクションに参加させる方法を示しています。The following example shows how to enlist such an object as a participant in a transaction using the EnlistVolatile method.

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();
    }
}
    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

パフォーマンスの最適化Optimizing Performance

Transaction クラスは、PSPE (Promotable Single Phase Enlistment) を参加させるための EnlistPromotableSinglePhase メソッドも提供しています。The Transaction class also provides the EnlistPromotableSinglePhase method to enlist a Promotable Single Phase Enlistment (PSPE). これにより、永続的リソース マネージャー (RM) は、MSDTC による管理のために後で必要に応じてエスカレートできるトランザクションをホストおよび "所有" できます。This allows a durable resource manager (RM) to host and "own" a transaction that can later be escalated to be managed by the MSDTC if necessary. 詳細については、「単一フェーズコミットと昇格可能単一フェーズ通知を使用した最適化」を参照してください。For more information on this, see Optimization using Single Phase Commit and Promotable Single Phase Notification.

関連項目See also