Eintragen von Ressourcen als Teilnehmer an einer Transaktion

[Dieses Thema ist Teil der Vorabdokumentation und kann in zukünftigen Versionen geändert werden. Leere Themen wurden als Platzhalter eingefügt.]

Jede an einer Transaktion teilnehmende Ressource wird von einem Ressourcen-Manager (RM) verwaltet, dessen Aktionen von einem Transaktions-Manager (TM) koordiniert werden. Die Koordination erfolgt anhand von Benachrichtigungen, die Abonnenten übermittelt werden, die sich über den TM in eine Transaktion eingetragen haben.

In diesem Thema wird beschrieben, wie eine oder mehrere Ressourcen in eine Transaktion eingetragen werden können. Zudem werden die verschiedenen Eintragungstypen erläutert. Im Thema Ausführen eines Einphasen- oder Mehrphasencommits für eine Transaktion wird erläutert, wie das Ausführen von Commits für Transaktionen unter eingetragenen Ressourcen koordiniert werden kann.

Eintragen von Ressourcen in eine Transaktion

Damit eine Ressource an einer Transaktion teilnehmen kann, muss sie sich in die Transaktion eintragen. Die Transaction-Klasse definiert eine Reihe von Methoden, deren Namen mit Enlist beginnen und die diese Funktionen bereitstellen. Die unterschiedlichen Enlist-Methoden entsprechen den verschiedenen Eintragungstypen, über die ein RM verfügen kann. Die EnlistVolatile-Methoden werden für flüchtige Ressourcen und die EnlistDurable-Methode wird für dauerhafte Ressourcen verwendet. Die Dauerhaftigkeit (oder im Gegensatz dazu die Flüchtigkeit) eines Ressourcen-Managers leitet sich davon ab, ob der Ressourcen-Manager die Wiederherstellung nach einem Fehler unterstützt. Wenn ein RM die Wiederherstellung nach einem Fehler unterstützt, legt er Daten während Phase 1 (Vorbereitung) in einem permanenten Speicher ab, damit er sich im Falle eines Ausfalls nach der Wiederherstellung erneut in die Transaktion eintragen und entsprechend den Benachrichtigungen des TM geeignete Aktionen ausführen kann. Im Allgemeinen verwalten flüchtige RMs flüchtige Ressourcen wie beispielsweise eine speicherinterne Datenstruktur (z. B. eine speicherinterne Transaktions-Hashtabelle), und dauerhafte RMs verwalten Ressourcen, die einen beständigeren Sicherungsspeicher haben (z. B. eine Datenbank, deren Sicherungsspeicher ein Datenträger ist).

Nachdem auf der Grundlage der Dauerhaftigkeit Ihrer Ressource entschieden wurde, ob die EnlistDurable-Methode oder die EnlistVolatile-Methode verwendet wird, sollten Sie Ihre Ressource für die Teilnahme an einem Zweiphasencommit (2PC) eintragen, indem Sie die IEnlistmentNotification-Schnittstelle für Ihren RM implementieren. Weitere Informationen zum Zweiphasencommit finden Sie unter Ausführen eines Einphasen- oder Mehrphasencommits für eine Transaktion.

Ein einzelner Teilnehmer kann sich für mehrere dieser Protokolle eintragen, indem er EnlistDurable und EnlistVolatile mehrmals aufruft.

Dauerhafte Eintragung

Die EnlistDurable-Methoden werden verwendet, um einen RM zur Teilnahme an der Transaktion als dauerhafte Ressource einzutragen. Wenn ein dauerhafter RM während einer Transaktion durch eine Unterbrechung ausfällt, wird erwartet, dass er eine Wiederherstellung durchführen kann, sobald er wieder online ist, indem er sich erneut (mithilfe der Reenlist-Methode) in alle Transaktionen einträgt, an denen er teilgenommen und für die er die Phase 2 nicht abgeschlossen hat. Nach Beendigung des Wiederherstellungsprozesses muss er zudem RecoveryComplete aufrufen. Weitere Informationen zur Wiederherstellung finden Sie unter Durchführen einer Wiederherstellung.

Die EnlistDurable-Methoden nehmen alle ein Guid-Objekt als ersten Parameter an. Guid wird vom TM dazu verwendet, eine dauerhafte Eintragung einem bestimmten RM zuzuordnen. Daher ist es zwingend erforderlich, dass ein RM dieselbe Guid-Identifikation verwendet (selbst bei einem Neustart mit mehreren RMs), da ansonsten die Wiederherstellung fehlschlagen kann.

Der zweite Parameter der EnlistDurable-Methode ist ein Verweis auf das Objekt, das der RM implementiert, um Transaktionsbenachrichtigungen zu erhalten. Die von Ihnen verwendete Überladung informiert den TM darüber, ob Ihr RM die Einphasencommit(SPC)-Optimierung unterstützt. Meist empfiehlt sich die Implementierung der IEnlistmentNotification-Schnittstelle, um an einem Zweiphasencommit (2PC) teilzunehmen. Wenn Sie den Commitvorgang jedoch optimieren möchten, können Sie die ISinglePhaseNotification-Schnittstelle für das Einphasencommit implementieren. Weitere Informationen zum Einphasencommit finden Sie unter Ausführen eines Einphasen- oder Mehrphasencommits für eine Transaktion und Optimierung mit Einphasencommit und heraufstufbarer Einphasenbenachrichtigung.

Der dritte Parameter ist eine EnlistmentOptions-Enumeration, deren Wert None oder EnlistDuringPrepareRequired sein kann. Wenn der Wert auf EnlistDuringPrepareRequired festgelegt ist, kann die Eintragung bei Erhalt der Vorbereitungsbenachrichtigung vom TM weitere RMs aufnehmen. Jedoch sollten Sie bedenken, dass für diesen Eintragungstyp keine Einphasencommit-Optimierung möglich ist.

Flüchtige Eintragung

Teilnehmer, die flüchtige Ressourcen, wie z. B. einen Cache, verwalten, sollten sich mithilfe der EnlistVolatile-Methoden eintragen. Diese Objekte sind möglicherweise nicht in der Lage, nach einem Systemausfall das Ergebnis einer Transaktion zu empfangen oder den Status der Transaktion, an der sie teilnehmen, wiederherzustellen.

Wie zuvor bereits ausgeführt, nimmt ein RM eine flüchtige Eintragung vor, wenn er eine speicherinterne, flüchtige Ressource verwaltet. Einer der Vorteile der Verwendung von EnlistVolatile besteht darin, dass keine unnötige Eskalation der Transaktion erzwungen wird. Weitere Informationen zu Transaktionseskalation finden Sie im Thema Eskalation der Transaktionsverwaltung. Eine flüchtige Eintragung impliziert einerseits einen Unterschied in der Handhabung der Eintragung durch den TM und andererseits einen Unterschied darin, was der TM vom RM erwartet. Das liegt daran, dass ein flüchtiger Ressourcen-Manager keine Wiederherstellung durchführt. Die EnlistVolatile-Methoden verwenden den Guid-Parameter nicht, weil ein flüchtiger Ressourcen-Manager keine Wiederherstellung durchführt und die Reenlist-Methode nicht aufruft, die Guid benötigt.

Wie bei den dauerhaften Eintragungen erkennt der TM an der Überladungsmethode, die Sie zur Eintragung verwenden, ob Ihr RM die Einphasencommit-Optimierung unterstützt. Da ein flüchtiger Ressourcen-Manager keine Wiederherstellung durchführen kann, werden während der Vorbereitungsphase für eine flüchtige Eintragung keine Wiederherstellungsinformationen geschrieben. Daher führt der Aufruf der RecoveryInformation-Methode zu InvalidOperationException.

Im folgenden Beispiel wird die Eintragung mithilfe der EnlistVolatile-Schnittstelle eines solchen Objekts als Teilnehmer in einer Transaktion veranschaulicht.

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

Optimieren der Leistung

Die Transaction-Klasse stellt die EnlistPromotableSinglePhase-Methode auch bereit, um eine Erweiterbare Einphaseneintragung (PSPE) vorzunehmen. Dadurch wird es einem dauerhaften RM ermöglicht, eine Transaktion zu hosten und zu "besitzen", die später bei Bedarf eskaliert werden kann, um von MSDTC verwaltet zu werden. Weitere Informationen hierzu finden Sie unter Optimierung mit Einphasencommit und heraufstufbarer Einphasenbenachrichtigung.

Siehe auch

Konzepte

Optimierung mit Einphasencommit und heraufstufbarer Einphasenbenachrichtigung
Ausführen eines Einphasen- oder Mehrphasencommits für eine Transaktion