Inscription de ressources comme participants à une transaction
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 explique comment l’engagement transactionnel peut être coordonné 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 ensemble de méthodes, dont les noms commencent par Enlist, qui fournissent ces fonctionnalités. Les différentes méthodes Enlist correspondent aux différents types d’inscription que peut avoir 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 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, si vous souhaitez optimiser le processus de validation, envisagez 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 é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 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 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.
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 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 sur ce problème, consultez Optimisation à l’aide de la validation à phase unique et de la notification à phase unique promotable.