Partager via


Mobilisation de ressources en tant que participants à une transaction

Chaque ressource participant à une transaction est gérée par un gestionnaire de ressources, dont les actions sont coordonnées par un gestionnaire de transactions. La coordination est effectuée par le biais de notifications données aux abonnés qui ont inscrit une transaction par le biais du gestionnaire de transactions.

Cette rubrique explique comment une ressource (ou plusieurs ressources) peut être inscrite dans une transaction, ainsi que les différents types d’inscription. La rubrique Validation d'une transaction en une phase unique et en plusieurs phases explique comment l’engagement transactionnel peut être coordonné entre les ressources inscrites.

Recrutement de ressources dans une transaction

Pour qu’une ressource participe à une transaction, elle doit s’inscrire dans la transaction. La Transaction classe définit un ensemble de méthodes dont les noms commencent par Enlist qui fournissent cette fonctionnalité. Les différentes méthodes d’inscription correspondent aux différents types d’inscription qu’un gestionnaire de ressources peut avoir. Plus précisément, vous utilisez les EnlistVolatile méthodes pour les ressources volatiles et la EnlistDurable méthode pour les ressources durables. La durabilité (ou inversement la volatilité) d’un gestionnaire de ressources fait référence à la prise en charge de la récupération des défaillances. Si un gestionnaire de ressources prend en charge la récupération après défaillance, il conserve les données par stockage durable lors de la Phase1 (préparation). Ainsi, s'il connaît une défaillance, il peut à nouveau s'inscrire à la transaction après récupération et procéder aux actions indiquées par les notifications envoyées par le gestionnaire de transactions. En général, les gestionnaires de ressources volatiles gèrent des ressources volatiles telles qu’une structure de données en mémoire (par exemple, une table de hachage transactionnée en mémoire) et les gestionnaires de ressources durables gèrent les ressources qui ont un magasin de stockage plus persistant (par exemple, une base de données dont le magasin de stockage est le disque).

Par souci de simplicité, après avoir décidé d’utiliser la méthode EnlistDurable ou EnlistVolatile en fonction de la prise en charge de la durabilité de votre ressource, vous devez ajouter votre ressource pour participer à l'engagement en deux phases (2PC) en implémentant l’interface IEnlistmentNotification pour votre gestionnaire de ressources. Pour plus d’informations sur la validation en deux phases, consultez Validation d’une transaction en une seule phase et en plusieurs phases.

Un seul participant peut s’inscrire pour plusieurs de ces protocoles en appelant EnlistDurable et EnlistVolatile plusieurs fois.

Inscription durable

Les méthodes EnlistDurable permettent d'inscrire un gestionnaire de ressources à une transaction en tant de ressource durable. Il est prévu que si un gestionnaire de ressources durable est interrompu au milieu d'une transaction, il peut effectuer une récupération une fois qu'il est remis en ligne en se réinscrivant (en utilisant la méthode Reenlist) dans toutes les transactions auxquelles il participait et n'a pas terminé la phase 2, et appeler RecoveryComplete une fois qu'il a terminé le processus de récupération. Pour plus d’informations sur la récupération, consultez Exécution de la récupération.

Les EnlistDurable méthodes prennent tous un Guid objet comme premier paramètre. Le composant Guid est utilisé par le gestionnaire de transactions pour associer une participation durable à un gestionnaire de ressources particulier. Par conséquent, il est impératif qu'un gestionnaire de ressources utilise de manière cohérente le même Guid pour s'identifier, même lorsque différents gestionnaires de ressources redémarrent, sinon la récupération peut échouer.

Le deuxième paramètre de la EnlistDurable méthode est une référence à l’objet que le gestionnaire de ressources implémente pour recevoir des notifications de transaction. La surcharge que vous utilisez indique au gestionnaire de transactions si votre gestionnaire de ressources prend en charge l'optimisation de validation à phase unique (SPC). La plupart du temps, vous implémentez l’interface IEnlistmentNotification pour participer à Two-Phase Commit (2PC). Toutefois, si vous souhaitez optimiser le processus de validation, vous pouvez envisager d’implémenter l’interface ISinglePhaseNotification pour SPC. Pour plus d’informations sur SPC, consultez Validation d'une transaction en une phase unique et en plusieurs phases et Optimisation à l'aide de la validation à phase unique et de la notification de phase unique pouvant être promue.

Le troisième paramètre est une EnlistmentOptions énumération, dont la valeur peut être ou NoneEnlistDuringPrepareRequired. Si la valeur est EnlistDuringPrepareRequired, l'inscription peut autoriser des gestionnaires de ressources supplémentaires après réception de la notification de préparation envoyée par le gestionnaire de transactions. Toutefois, vous devez savoir que ce type d’inscription n’est pas éligible à l’optimisation Single Phase Commit.

Recrutement instable

Les participants gérant des ressources volatiles telles qu’un cache doivent s’inscrire à l’aide des EnlistVolatile méthodes. Ces objets peuvent ne pas être en mesure d’obtenir le résultat d’une transaction ou de récupérer l’état de toute transaction qu’ils participent après une défaillance système.

Comme indiqué précédemment, un gestionnaire de ressources effectuerait une inscription volatile s’il gère une ressource volatile en mémoire. L’un des avantages de l’utilisation EnlistVolatile est qu’il ne force pas une escalade inutile de la transaction. Pour plus d’informations sur l’escalade des transactions, consultez la rubrique Escalade de la gestion des transactions . Une inscription volatile implique une différence de traitement de l'inscription par le gestionnaire de transactions, ainsi qu'une modification des attentes du gestionnaire de transactions concernant le gestionnaire de ressources. Cela est dû au fait qu’un gestionnaire de ressources volatile n’effectue pas de récupération. Les EnlistVolatile méthodes ne prennent pas de Guid paramètre, car un gestionnaire de ressources volatile n’effectue pas de récupération et n’appelle pas la Reenlist méthode qui a besoin d’un Guid.

Comme pour les inscriptions durables, quelle que soit la méthode de surcharge que vous utilisez pour l'enregistrement, cela informe le gestionnaire de transactions si votre gestionnaire de ressources prend en charge l’optimisation de validation en une seule phase. Étant donné qu’un gestionnaire de ressources volatiles ne peut pas effectuer de récupération, aucune information de récupération n’est écrite pour une inscription volatile pendant la phase de préparation. Par conséquent, l’appel de la RecoveryInformation méthode entraîne un InvalidOperationException.

L’exemple suivant montre comment inscrire un tel objet en tant que participant à une transaction à l’aide de la EnlistVolatile méthode.

static void Main(string[] args)
{
    try
    {
        using (TransactionScope scope = new TransactionScope())
        {

            //Create an enlistment object
            myEnlistmentClass myEnlistment = new myEnlistmentClass();

            //Enlist on the current transaction with the enlistment object
            Transaction.Current.EnlistVolatile(myEnlistment, 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 in doubt 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 in doubt notification is received

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

Optimisation des performances

La classe Transaction fournit également la méthode EnlistPromotableSinglePhase permettant de s'inscrire à une PSPE (Promotable Single Phase Enlistment). Cela permet à un gestionnaire de ressources durable (RM) d’héberger et de « posséder » une transaction qui peut ultérieurement être réaffectée pour être gérée par le MSDTC si nécessaire. Pour plus d’informations sur ce problème, consultez Optimisation à l’aide de la validation à phase unique et de la notification à phase unique promotable.

Voir aussi