Delen via


Een transactie doorvoeren in één fase en meerdere fasen

Elke resource die in een transactie wordt gebruikt, wordt beheerd door een resourcemanager (RM), waarvan de acties worden gecoördineerd door een transaction manager (TM). In het onderwerp Resources in een transactielijst wordt besproken hoe een resource (of meerdere resources) kan worden opgenomen in een transactie. In dit onderwerp wordt besproken hoe transactietoezegging kan worden gecoördineerd tussen in de lijst vermelde resources.

Aan het einde van de transactie vraagt de toepassing om de transactie vast te zetten of terug te draaien. De transactiemanager moet risico's elimineren, zoals sommige resourcemanagers die stemmen om door te voeren, terwijl anderen stemmen om de transactie terug te draaien.

Als uw transactie meer dan één resource omvat, moet u een doorvoer met twee fasen (2PC) uitvoeren. Het protocol voor doorvoeren in twee fasen (de voorbereidingsfase en de doorvoerfase) zorgt ervoor dat wanneer de transactie wordt beëindigd, alle wijzigingen in alle resources volledig worden doorgevoerd of volledig worden teruggedraaid. Alle deelnemers worden vervolgens op de hoogte gesteld van het uiteindelijke resultaat. Raadpleeg het boek "Transaction Processing : Concepts and Techniques (Morgan Kaufmann Series in Gegevensbeheer Systems) ISBN:1558601902" van Jim Gray voor een gedetailleerde bespreking van het protocol voor doorvoeren in twee fasen.

U kunt de prestaties van uw transactie ook optimaliseren door deel te nemen aan het protocol Voor één fase doorvoeren. Zie Optimalisatie met single phase Commit en Promotable Single Phase Notification voor meer informatie.

Als u alleen wilt worden geïnformeerd over het resultaat van een transactie en niet wilt deelnemen aan stemmen, moet u zich registreren voor de TransactionCompleted gebeurtenis.

Doorvoeren in twee fasen (2PC)

In de eerste transactiefase vraagt de transactiebeheerder elke resource op om te bepalen of een transactie moet worden doorgevoerd of teruggedraaid. In de tweede transactiefase meldt de transactiebeheerder elke resource van het resultaat van de query's, zodat deze de benodigde opschoning kan uitvoeren.

Om deel te nemen aan dit soort transacties, moet een resourcemanager de IEnlistmentNotification interface implementeren, die methoden biedt die door de TM worden aangeroepen als meldingen tijdens een 2PC. In het volgende voorbeeld ziet u een voorbeeld van een dergelijke implementatie.

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

Fase voorbereiden (fase 1)

Na ontvangst van een Commit aanvraag van de toepassing begint de transactiemanager met de voorbereidingsfase van alle ingeschreven deelnemers door de Prepare methode aan te roepen voor elke ingeschreven resource, om de stem van elke resource op de transactie te verkrijgen.

Uw resourcemanager die de IEnlistmentNotification interface implementeert, moet eerst de Prepare(PreparingEnlistment) methode implementeren, zoals in het volgende eenvoudige voorbeeld wordt weergegeven.

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;  
     }  
}  

Wanneer de duurzame resourcemanager deze aanroep ontvangt, moet deze de herstelgegevens van de transactie registreren (beschikbaar door de RecoveryInformation eigenschap op te halen) en welke informatie nodig is om de transactie bij doorvoer te voltooien. Dit hoeft niet binnen de Prepare methode te worden uitgevoerd omdat de RM dit kan doen op een werkrolthread.

Wanneer de RM klaar is met het voorbereiden van het werk, moet deze stemmen op doorvoeren of terugdraaien door de Prepared of ForceRollback methode aan te roepen. U ziet dat de PreparingEnlistment klasse een Done methode over neemt van de Enlistment klasse. Als u deze methode aanroept in de callback tijdens de PreparingEnlistment voorbereidingsfase, wordt de TM ervan op de hoogte gesteld dat het een alleen-lezen opname is (dat wil zeggen resourcebeheerders die gegevens met transactiebeveiliging kunnen lezen maar niet kunnen bijwerken) en dat de RM geen verdere meldingen ontvangt over het resultaat van de transactie in fase 2.

De toepassing wordt verteld over de succesvolle toezegging van de transactie nadat alle resourcemanagers hebben gestemd Prepared.

Doorvoerfase (fase 2)

Als de transactie in de tweede fase van de transactie een geslaagde voorbereiding ontvangt van alle resourcemanagers (alle resourcemanagers die aan het einde van fase 1 zijn aangeroepen Prepared ), wordt de Commit methode voor elke resourcemanager aangeroepen. De resourcemanagers kunnen vervolgens de wijzigingen duurzaam aanbrengen en de doorvoer voltooien.

Als een resourcemanager een fout heeft gerapporteerd om zich voor te bereiden in fase 1, roept de transactiebeheerder de Rollback methode aan voor elke resourcemanager en geeft deze de fout aan van de doorvoer naar de toepassing.

Uw Resource Manager moet dus de volgende methoden implementeren.

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();
}  

De RM moet alle benodigde werkzaamheden uitvoeren om de transactie te voltooien op basis van het meldingstype en de TM informeren dat deze is voltooid door de methode aan te roepen Done voor de Enlistment parameter. Dit werk kan worden uitgevoerd op een werkrolthread. Houd er rekening mee dat de meldingen van fase 2 inline kunnen plaatsvinden op dezelfde thread die de Prepared methode in fase 1 wordt genoemd. Als zodanig moet u geen werk doen na de Prepared aanroep (bijvoorbeeld het vrijgeven van vergrendelingen) die u verwacht te hebben voltooid voordat u de meldingen van fase 2 ontvangt.

InDoubt implementeren

Ten slotte moet u de InDoubt methode voor de vluchtige resourcemanager implementeren. Deze methode wordt aangeroepen als de transactiemanager geen contact meer heeft met een of meer deelnemers, zodat hun status onbekend is. Als dit gebeurt, moet u dit feit vastleggen, zodat u later kunt onderzoeken of een van de transactiedeelnemers een inconsistente status heeft.

public void InDoubt (Enlistment enlistment)  
{  
     // log this  
     enlistment.Done();  
}  

Optimalisatie van doorvoeren met één fase

Het protocol Single Phase Commit is efficiënter tijdens runtime, omdat alle updates worden uitgevoerd zonder expliciete coördinatie. Zie Optimalisatie met behulp van single phase commit en Promotable Single Phase Notification voor meer informatie over dit protocol.

Zie ook