Eintragen von Ressourcen als Teilnehmer an einer Transaktion
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 beschrieben, wie ein Transaktionscommit 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 Ressourcen-Manager 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 über einen beständigeren Sicherungsspeicher verfügen (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 zu 2PC 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 zu SPC 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 zur Transaktionseskalation finden Sie im Thema Eskalation der Transaktionsverwaltung. Eine flüchtige Eintragung impliziert einerseits einen Unterschied in der Handhabung der Eintragung durch den Transaktions-Manager und andererseits einen Unterschied darin, was der Transaktions-Manager vom Ressourcen-Manager 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.
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
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.