Inscription de ressources comme participants à une transaction

[Cette rubrique est une documentation préliminaire et peut faire l'objet de modifications dans les versions à venir. Les rubriques vides sont incluses comme espaces réservés.]

Les ressources participant à une transaction sont managées par un gestionnaire de ressources, dont les actions sont coordonnées par un gestionnaire de transactions. La coordination s'effectue par envoi de notifications aux abonnés qui se sont inscrits à une transaction via le gestionnaire de transactions.

Cette rubrique explique comment inscrire une ressource (ou plusieurs ressources) à une transaction et traite des différents types d'inscription. La rubrique Validation d'une transaction en une phase unique et en plusieurs phases traite de la coordination de la validation d'une transaction entre les ressources inscrites.

Inscription de ressources à une transaction

Pour qu'une ressource participe à une transaction, elle doit être inscrite à cette transaction. La classe Transaction définit un jeu de méthodes, dont les noms commencent par Enlist, qui fournit cette fonctionnalité. Les différentes méthodes Enlist correspondent aux différents types d'inscription dont peut disposer un gestionnaire de ressources. En particulier, utilisez les méthodes EnlistVolatile pour les ressources volatiles et la méthode EnlistDurable pour les ressources durables. La durabilité (ou à l'inverse la volatilité) d'un gestionnaire de ressources indique s'il prend en charge la récupération après défaillance. 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 les ressources volatiles, comme une structure de données en mémoire (par exemple, une table de hachage traitée en mémoire), et les gestionnaires de ressources durables gèrent les ressources qui disposent d'un magasin de stockage plus persistant (par exemple, une base de données ayant un disque comme magasin de stockage).

Pour une question de simplicité, après avoir décidé d'utiliser la méthode EnlistDurable ou la méthode EnlistVolatile, selon la prise en charge de la durabilité de la ressource, inscrivez votre ressource pour participer à la validation en deux phases (2PC) en implémentant l'interface IEnlistmentNotification de votre gestionnaire de ressources. Pour plus d'informations sur le protocole 2PC, consultez Validation d'une transaction en une phase unique et en plusieurs phases.

Un participant peut s'inscrire à plusieurs de ces protocoles en appelant EnlistDurable et EnlistVolatile à plusieurs reprises.

Inscription durable

Les méthodes EnlistDurable permettent d'inscrire un gestionnaire de ressources à une transaction en tant de ressource durable. Si un gestionnaire de ressources durables s'arrête en cours de transaction, il peut procéder à la récupération une fois sa remise en ligne effectuée par réinscription (à l'aide de la méthode Reenlist) à toutes les transactions auxquelles il participait et dont il n'a pas terminé la phase 2, et appeler RecoveryComplete une fois le traitement de récupération terminé. Pour plus d'informations sur la récupération, consultez Exécution de la récupération.

Les méthodes EnlistDurable ont toutes un objet Guid pour premier paramètre. Le gestionnaire de transactions utilise le Guid pour associer une inscription durable à un gestionnaire de ressources particulier. Il est donc impératif qu'un gestionnaire de ressources utilise toujours le même Guid pour son identification après redémarrage, même sur plusieurs gestionnaires de ressources, sous peine de faire échouer la récupération.

Le second paramètre des méthodes EnlistDurable est une référence à l'objet que le gestionnaire de ressources implémente pour recevoir les 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). Dans la plupart des cas, vous implémenterez l'interface IEnlistmentNotification pour participer à la validation en deux phases (2PC). Cependant, pour optimiser le processus de validation, vous pouvez implémenter l'interface ISinglePhaseNotification pour SPC. Pour plus d'informations sur la 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 énumération EnlistmentOptions, dont la valeur peut être None ou EnlistDuringPrepareRequired. 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 pris en charge pour l'optimisation de la validation en une phase.

Inscription volatile

Les participants gérant des ressources volatiles telles qu'un cache doivent s'inscrire à l'aide des méthodes EnlistVolatile. Il est possible que ces objets ne puissent pas obtenir le résultat d'une transaction ou récupérer l'état d'une transaction à laquelle ils participent après une défaillance système.

Comme indiqué précédemment, un gestionnaire de ressources procède à une inscription volatile s'il manage une ressource volatile en mémoire. L'un des avantages offert par EnlistVolatile est que cela évite une remontée inutile de la transaction. Pour plus d'informations sur la remontée des transactions, consultez la rubrique Remontée 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 que les gestionnaires de ressources volatiles ne prennent pas en charge la récupération. Les méthodes EnlistVolatile n'ont pas de paramètre Guid car les gestionnaires de ressources volatiles ne prennent pas en charge la récupération et n'appellent donc jamais la méthode Reenlist, qui requiert un Guid.

Comme pour les inscriptions durables, la méthode de surcharge utilisée pour vous inscrire indique au gestionnaire de transactions si votre gestionnaire de ressources prend en charge l'optimisation de la validation en une phase. Les gestionnaires de ressources volatiles ne prenant pas en charge la récupération, aucune information de récupération n'est déclarée pour une inscription volatile lors de la phase de préparation. C'est pourquoi appeler la méthode RecoveryInformation entraîne une InvalidOperationException.

L'exemple suivant indique comment inscrire l'un de ces objets à une transaction à l'aide de la méthode 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();
    }
}

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 durables d'héberger et de « posséder » une transaction qui peut, si nécessaire, être ensuite remontée pour être managée par le MSDTC. Pour plus d'informations, consultez Optimisation à l'aide de la validation à phase unique et de la notification de phase unique pouvant être promue.

Voir aussi

Concepts

Optimisation à l'aide de la validation à phase unique et de la notification de phase unique pouvant être promue
Validation d'une transaction en une phase unique et en plusieurs phases