Validation d'une transaction en une phase unique et en plusieurs phases
Les ressources utilisées dans une transaction sont managées par un gestionnaire de ressources, dont les actions sont coordonnées par un gestionnaire de transactions. La rubrique Inscription de ressources comme participants à une transaction explique comment inscrire une ressource (ou plusieurs ressources) à une transaction. Elle traite de la coordination de la validation d'une transaction entre les ressources inscrites.
À la fin de la transaction, l'application requiert que la transaction soit validée ou restaurée. Le gestionnaire de transactions doit éliminer tous les risques, par exemple des gestionnaires de ressources votant pour la validation de la transaction et d'autres votant pour sa restauration.
Si votre transaction implique plusieurs ressources, vous devez effectuer une validation en deux phases (2PC). Le protocole de validation en deux phases (une phase de préparation et une phase de validation) garantit, à la fin de la transaction, l'entière validation ou restauration de l'ensemble des modifications apportées aux ressources. Tous les participants sont ensuite informés du résultat final. Pour une présentation détaillée du protocole de validation en deux phases, consultez « Transaction Processing : Concepts and Techniques (Morgan Kaufmann Series in Data Management Systems) ISBN:1558601902 » de Jim Gray.
Vous pouvez également optimiser les performances de votre transaction en suivant le protocole de validation en une phase. Pour plus d’informations, consultez Optimisation à l’aide de la validation à phase unique et de la notification de phase unique pouvant être promue.
Pour être informé du résultat d'une transaction sans participer au vote, inscrivez-vous à l'événement TransactionCompleted.
Validation en deux phases (2PC)
Lors de la première phase de transaction, le gestionnaire de transactions interroge chaque ressource afin de déterminer si la transaction doit être validée ou restaurée. Lors de la seconde phase de transaction, le gestionnaire de transactions informe chaque ressource du résultat de ses recherches, lui permettant d'effectuer les nettoyages nécessaires.
Pour participer à ce type de transaction, un gestionnaire de ressources doit implémenter l'interface IEnlistmentNotification, qui fournit des méthodes appelées par le gestionnaire de transactions en tant que notifications, au cours d'une validation en deux phases (2PC). L'exemple suivant illustre une implémentation de ce type.
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 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
Phase de préparation (Phase 1)
À la réception d'une requête Commit de l'application, le gestionnaire de transactions lance la phase de préparation des participants inscrits en appelant la méthode Prepare sur chaque ressource inscrite, afin d'obtenir leur vote concernant la transaction.
Le gestionnaire de ressources qui implémente l'interface IEnlistmentNotification doit d'abord implémenter la méthode Prepare(PreparingEnlistment), comme illustré par l'exemple simple suivant.
public void Prepare(PreparingEnlistment preparingEnlistment)
{
Console.WriteLine("Prepare notification received");
//Perform work
Console.Write("reply with prepared? [Y|N] ");
c = Console.ReadKey();
Console.WriteLine();
//If work finished correctly, reply with prepared
if ((c.KeyChar == 'Y') || (c.KeyChar == 'y'))
{
preparingEnlistment.Prepared();
break;
}
// otherwise, do a ForceRollback
else if ((c.KeyChar == 'N') || (c.KeyChar == 'n'))
{
preparingEnlistment.ForceRollback();
break;
}
}
Lorsque le gestionnaire de ressources durables reçoit cet appel, il doit consigner les informations de récupération de la transaction (disponibles par récupération de la propriété RecoveryInformation) ainsi que l'ensemble des informations nécessaires pour terminer la transaction en cours de validation. Il n'est pas nécessaire d'effectuer cette opération au sein de la méthode Prepare car le gestionnaire de ressources peut le faire sur un thread de travail.
Une fois que le gestionnaire de ressources a terminé son travail de préparation, il doit voter pour la validation ou la restauration en appelant la méthode Prepared ou ForceRollback. Notez que la classe PreparingEnlistment hérite d'une méthode Done de la classe Enlistment. L'appel à cette méthode sur le rappel PreparingEnlistment au cours de la phase de préparation indique au gestionnaire de transactions qu'il s'agit d'une inscription en lecture seule (des gestionnaires de ressources qui peuvent être lus mais qui ne peuvent pas mettre à jour les données protégées par la transaction) et le gestionnaire de ressources ne reçoit plus de notification du gestionnaire de transaction jusqu'au résultat de la transaction en phase 2.
L'application est informée de la validation réussie de la transaction après le vote Prepared de tous les gestionnaires de ressources
Phase de validation (Phase 2)
Lors de la seconde phase de la transaction, si le gestionnaire de transactions a reçu les préparations réussies de tous les gestionnaires de ressources (c'est-à-dire, si tous les gestionnaires de ressources ont appelé Prepared à la fin de la phase 1), il appelle la méthode Commit pour chaque gestionnaire de ressources. Les gestionnaires de ressources peuvent ensuite confirmer les modifications et terminer la validation.
Si l'un des gestionnaires de ressources signale un échec de préparation en phase 1, le gestionnaire de transactions appelle la méthode Rollback pour chaque gestionnaire de ressources et communique l'échec de la validation à l'application.
C'est pourquoi votre gestionnaire de ressources doit implémenter les méthodes suivantes.
public void Commit (Enlistment enlistment)
{
// Do any work necessary when commit notification is received
// Declare done on the enlistment
enlistment.Done();
}
public void Rollback (Enlistment enlistment)
{
// Do any work necessary when rollback notification is received
// Declare done on the enlistment
enlistment.Done();
}
Le gestionnaire de ressources doit effectuer le nécessaire pour terminer la transaction d'après le type de notification, puis en informer le gestionnaire de transactions en appelant la méthode Done sur le paramètre Enlistment. Cela peut s'effectuer sur un thread de travail. Notez que les notifications de la phase 2 peuvent se produire en ligne sur le même thread qui a appelé la méthode Prepared de la phase 1. Par conséquent, vous ne devez effectuer aucun travail après l'appel Prepared (par exemple, libérer des verrous) que vous devez avoir terminé avant de recevoir les notifications de phase 2.
Implémentation de la méthode InDoubt
Enfin, implémentez la méthode InDoubt pour le gestionnaire de ressources volatiles. Cette méthode est appelée si le gestionnaire de transactions perd contact avec un ou plusieurs participants, rendant leur état inconnu. Dans ce cas, consignez ce fait afin de pouvoir ensuite contrôler si des participants à la transaction ont été laissés dans un état incohérent.
public void InDoubt (Enlistment enlistment)
{
// log this
enlistment.Done();
}
Optimisation de la validation en une phase
Le protocole de validation en une phase est plus efficace lors de l'exécution car toutes les mises à jour sont effectuées sans coordination explicite. Pour plus d’informations sur ce protocole, consultez Optimisation à l’aide de la validation à phase unique et de la notification de phase unique pouvant être promue.