Dela via


Registrera resurser som deltagare i en transaktion

Varje resurs som deltar i en transaktion hanteras av en resurshanterare vars åtgärder samordnas av en transaktionshanterare. Samordningen sker via meddelanden som ges till prenumeranter som har registrerat sig i en transaktion via transaktionshanteraren.

Det här avsnittet beskriver hur en resurs (eller flera resurser) kan registreras i en transaktion, samt de olika typerna av enlistning. Avsnittet Genomför en transaktion i enfas och flera faser beskriver hur transaktionsåtagandet kan samordnas mellan registrerade resurser.

Registrera resurser i en transaktion

För att en resurs ska kunna delta i en transaktion måste den registrera sig i transaktionen. Klassen Transaction definierar en uppsättning metoder vars namn börjar med Enlist som tillhandahåller den här funktionen. De olika metoderna för att lista motsvarar de olika typer av enlistning som en resurshanterare kan ha. Mer specifikt använder EnlistVolatile du metoderna för flyktiga resurser och EnlistDurable metoden för varaktiga resurser. Hållbarheten (eller omvänt volatiliteten) för en resurshanterare refererar till om resurshanteraren stöder återställning av fel. Om en resurshanterare stöder haveriberedskap bevarar den data till varaktig lagring under Fas1 (förbereda) så att om resurshanteraren slutar fungera kan den återlista transaktionen vid återställning och utföra rätt åtgärder baserat på de meddelanden som tas emot från TM. I allmänhet hanterar flyktiga resurshanterare flyktiga resurser, till exempel en minnesintern datastruktur (till exempel en transacted-hashtable i minnet) och hållbara resurshanterare hanterar resurser som har ett mer beständigt lagringslager (till exempel en databas vars lagringsplats är disk).

För enkelhetens EnlistDurable skull bör du, när du har bestämt dig för om du vill använda metoden eller EnlistVolatile baserat på resursens hållbarhetsstöd, registrera resursen IEnlistmentNotification för att delta i Två fasincheckning (2PC) genom att implementera gränssnittet för resurshanteraren. Mer information om 2PC finns i Checka in en transaktion i enfas och flera faser.

En enskild deltagare kan registrera sig för fler än ett av dessa protokoll genom att anropa EnlistDurable och EnlistVolatile flera gånger.

Durable Enlistment

Metoderna EnlistDurable används för att registrera en resurshanterare för deltagande i transaktionen som en beständig resurs. Om en beständig resurshanterare tas ned mitt i en transaktion kan den utföra återställning när den är online igen genom att återlista (med Reenlist hjälp av metoden) i alla transaktioner där den var deltagare och inte slutförde fas 2 och anropa RecoveryComplete när återställningen har slutförts. Mer information om återställning finns i Utföra återställning.

Metoderna EnlistDurable tar alla ett Guid objekt som sin första parameter. Guid Används av transaktionshanteraren för att associera en varaktig registrering med en viss resurshanterare. Därför är det absolut nödvändigt att en resurshanterare konsekvent använder samma Guid för att identifiera sig även mellan olika resurshanterare vid omstart, annars kan återställningen misslyckas.

Den andra parametern för EnlistDurable metoden är en referens till det objekt som resurshanteraren implementerar för att ta emot transaktionsmeddelanden. Den överlagring som du använder informerar transaktionshanteraren om din resurshanterare stöder SPC-optimering (Single Phase Commit). För det mesta implementerar IEnlistmentNotification du gränssnittet för att delta i tvåfasincheckning (2PC). Men om du vill optimera incheckningsprocessen kan du överväga att implementera ISinglePhaseNotification gränssnittet för SPC. Mer information om SPC finns i Commiting a Transaction in Single-Phase and Multi-Phase and Optimization using Single Phase Commit and Promotable Single Phase Notification (Genomför en transaktion i enfas och flera faser och optimering med hjälp av enfasincheckning och meddelande om enkel fas i promotable).

Den tredje parametern är en EnlistmentOptions uppräkning vars värde kan vara antingen None eller EnlistDuringPrepareRequired. Om värdet är inställt på EnlistDuringPrepareRequiredkan enlistningen registrera ytterligare resurshanterare när du tar emot Förbered-meddelandet från transaktionshanteraren. Du bör dock vara medveten om att den här typen av registrering inte är berättigad till optimering av enfasincheckning.

Flyktig registrering

Deltagare som hanterar flyktiga resurser, till exempel en cache, bör registrera sig med hjälp av EnlistVolatile metoderna. Sådana objekt kanske inte kan erhålla resultatet av en transaktion eller återställa tillståndet för en transaktion som de deltar i efter ett systemfel.

Som tidigare nämnts skulle en resurshanterare göra en flyktig registrering om den hanterar en minnesintern, flyktig resurs. En av fördelarna med att använda EnlistVolatile är att den inte tvingar fram en onödig eskalering av transaktionen. Mer information om transaktionseskalering finns i avsnittet Om eskalering av transaktionshantering. Att registrera volatiliteten innebär både en skillnad i hur enlistningen hanteras av transaktionshanteraren, samt vad som förväntas av resurshanteraren av transaktionshanteraren. Det beror på att en beständig resurshanterare inte utför återställning. Metoderna EnlistVolatile tar Guid ingen parameter eftersom en beständig resurshanterare inte utför återställning och inte anropar metoden Reenlist som behöver en Guid.

Precis som med varaktiga registreringar anger den överlagringsmetod som du använder för att ange för transaktionshanteraren om resurshanteraren stöder optimering av enfasincheckning. Eftersom en beständig resurshanterare inte kan utföra återställning skrivs ingen återställningsinformation för en flyktig registrering under förberedelsefasen. Därför resulterar anropet av RecoveryInformation metoden i en InvalidOperationException.

I följande exempel visas hur du registrerar ett sådant objekt som en deltagare i en transaktion med hjälp av EnlistVolatile metoden .

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

Optimera prestanda

Klassen Transaction innehåller också metoden EnlistPromotableSinglePhase för att registrera en PSPE (Promotable Single Phase Enlistment). På så sätt kan en beständig resurshanterare (RM) vara värd för och "äga" en transaktion som senare kan eskaleras till att hanteras av MSDTC om det behövs. Mer information om detta finns i Optimering med hjälp av enfasincheckning och meddelande om enkel fas i kampanjtabell.

Se även