Genomföra en transaktion i enfas och flera faser
Varje resurs som används i en transaktion hanteras av en resurshanterare (RM), vars åtgärder samordnas av en transaktionshanterare (TM). Avsnittet Enlisting Resources as Participants in a Transaction (Enlisting Resources as Participants in a Transaction ) beskriver hur en resurs (eller flera resurser) kan registreras i en transaktion. I det här avsnittet beskrivs hur transaktionsåtagandet kan samordnas mellan registrerade resurser.
I slutet av transaktionen begär programmet att transaktionen antingen checkas in eller återställs. Transaktionshanteraren måste eliminera risker som att vissa resurshanterare röstar för att checka in medan andra röstar för att återställa transaktionen.
Om transaktionen omfattar mer än en resurs måste du utföra en tvåfas incheckning (2PC). Tvåfas-incheckningsprotokollet (förberedelsefasen och incheckningsfasen) säkerställer att alla ändringar i alla resurser antingen är helt genomförda eller helt återställda när transaktionen avslutas. Alla deltagare informeras sedan om slutresultatet. En detaljerad beskrivning av tvåfasprotokollet finns i boken "Transaction Processing : Concepts and Techniques (Morgan Kaufmann Series in Datahantering Systems) ISBN:1558601902" av Jim Gray.
Du kan också optimera transaktionens prestanda genom att delta i protokollet För genomförande av en fas. Mer information finns i Optimering med hjälp av enfasincheckning och meddelande om enkel fas i kampanjtabellen.
Om du bara vill bli informerad om en transaktions resultat och inte vill delta i röstningen bör du registrera dig för TransactionCompleted händelsen.
Tvåfasincheckning (2PC)
I den första transaktionsfasen frågar transaktionshanteraren varje resurs för att avgöra om en transaktion ska checkas in eller återställas. I den andra transaktionsfasen meddelar transaktionshanteraren varje resurs om resultatet av sina frågor, så att den kan utföra nödvändig rensning.
För att delta i den här typen av transaktion måste en resurshanterare implementera IEnlistmentNotification gränssnittet, som tillhandahåller metoder som anropas av TM som meddelanden under en 2PC. Följande exempel visar ett exempel på en sådan implementering.
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
Förbered fas (fas 1)
När du tar emot en Commit begäran från programmet påbörjar transaktionshanteraren förberedelsefasen för alla deltagare i listan genom att anropa Prepare metoden för varje listad resurs för att få varje resurss röst på transaktionen.
Din resurshanterare som implementerar IEnlistmentNotification gränssnittet bör först implementera Prepare(PreparingEnlistment) metoden, vilket visas i följande enkla exempel.
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;
}
}
När den hållbara resurshanteraren tar emot det här anropet bör den logga transaktionens återställningsinformation (tillgänglig genom att RecoveryInformation hämta egenskapen) och all information som krävs för att slutföra transaktionen vid incheckningen. Detta behöver inte utföras inom Prepare metoden eftersom RM kan göra detta på en arbetstråd.
När RM har slutfört sitt förberedelsearbete bör det rösta för att checka in eller återställa genom att anropa Prepared metoden eller ForceRollback . Observera att PreparingEnlistment klassen ärver en Done metod från Enlistment klassen. Om du anropar den här metoden på återanropet PreparingEnlistment under förberedelsefasen informerar den TM om att det är en skrivskyddad lista (det vill säga resurshanterare som kan läsa men inte kan uppdatera transaktionsskyddade data) och RM tar inte emot några ytterligare meddelanden från transaktionshanteraren om resultatet av transaktionen i fas 2.
Programmet får höra om transaktionens lyckade åtagande efter att alla resursansvariga har röstat Prepared.
Incheckningsfas (fas 2)
I den andra fasen av transaktionen, om transaktionshanteraren tar emot lyckade förberedelser från alla resurshanterare (alla resurshanterare har anropat Prepared i slutet av fas 1), anropas Commit metoden för varje resurshanterare. Resurshanterna kan sedan göra ändringarna beständiga och slutföra incheckningen.
Om någon resurshanterare rapporterade att det inte gick att förbereda i fas 1 anropar transaktionshanteraren Rollback metoden för varje resurshanterare och anger att incheckningen till programmet misslyckades.
Resurshanteraren bör därför implementera följande metoder.
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();
}
RM bör utföra allt arbete som krävs för att slutföra transaktionen baserat på meddelandetypen och informera TM om att den har slutförts genom att anropa Done metoden för parametern Enlistment . Det här arbetet kan utföras på en arbetstråd. Observera att fas 2-meddelanden kan ske i samma tråd som anropade Prepared metoden i fas 1. Därför bör du inte utföra något arbete efter anropet Prepared (till exempel frigöra lås) som du förväntar dig att ha slutfört innan du tar emot fas 2-meddelandena.
Implementera InDoubt
Slutligen bör du implementera InDoubt metoden för den flyktiga resurshanteraren. Den här metoden anropas om transaktionshanteraren förlorar kontakten med en eller flera deltagare, så deras status är okänd. Om detta inträffar bör du logga detta faktum så att du senare kan undersöka om någon av transaktionsdeltagarna har lämnats i ett inkonsekvent tillstånd.
public void InDoubt (Enlistment enlistment)
{
// log this
enlistment.Done();
}
Optimering av enfasincheckning
Protokollet För genomförande av en fas är effektivare vid körning eftersom alla uppdateringar görs utan någon explicit samordning. Mer information om det här protokollet finns i Optimization using Single Phase Commit and Promotable Single Phase Notification (Optimering med enfasincheckning och meddelande om enkel fas).