Partilhar via


Listando recursos como participantes de uma transação

Cada recurso que participa de uma transação é gerenciado por um gerente de recursos, cujas ações são coordenadas por um gerente de transações. A coordenação é feita através de notificações dadas aos assinantes que se inscreveram em uma transação através do gerente de transações.

Este tópico aborda como um recurso (ou vários recursos) pode ser alistado em uma transação, bem como os diferentes tipos de alistamento. O tópico Comprometendo uma transação em Single-Phase e Fase Múltipla aborda como o compromisso de uma transação pode ser coordenado entre os recursos alistados.

Recrutando recursos em uma transação

Para que um recurso participe de uma transação, ele deve se alistar na transação. A Transaction classe define um conjunto de métodos cujos nomes começam com Enlist que fornecem essa funcionalidade. Os diferentes métodos Enlist correspondem aos diferentes tipos de alistamento que um gerente de recursos pode ter. Especificamente, você usa os EnlistVolatile métodos para recursos voláteis e o EnlistDurable método para recursos duráveis. A durabilidade (ou, inversamente, a volatilidade) de um gestor de recursos refere-se ao facto de o gestor de recursos suportar a recuperação de falhas. Se um gerenciador de recursos oferecer suporte à recuperação de falhas, ele persistirá os dados para armazenamento durável durante a Fase 1 (preparação), de modo que, se o gerenciador de recursos ficar inativo, ele poderá se alistar novamente na transação após a recuperação e executar as ações adequadas com base nas notificações recebidas da TM. Em geral, os gerentes de recursos voláteis gerenciam recursos voláteis, como uma estrutura de dados na memória (por exemplo, um hashtable transacionado na memória), e os gerenciadores de recursos duráveis gerenciam recursos que têm um armazenamento de backup mais persistente (por exemplo, um banco de dados cujo armazenamento de backup é disco).

Para simplificar, depois de decidir se deve usar o método EnlistDurable ou o EnlistVolatile com base no suporte de durabilidade do seu recurso, deve-se inscrever o recurso para participar no Two Phase Commit (2PC), implementando a interface IEnlistmentNotification para o seu gerenciador de recursos. Para obter mais informações sobre o 2PC, consulte Confirmar uma transação no Single-Phase e nas fases múltiplas.

Um único participante pode se alistar para mais de um desses protocolos ligando EnlistDurable e EnlistVolatile várias vezes.

Alistamento durável

Os métodos EnlistDurable são usados para alistar um gestor de recursos para participar na transação como um recurso durável. Espera-se que, se um gestor de recursos duráveis for interrompido no meio de uma transação, ele possa realizar a recuperação assim que for colocado on-line novamente, reinscrevendo-se (usando o método Reenlist) em todas as transações nas quais foi participante e não concluiu a fase 2, e chamando RecoveryComplete assim que concluir o processamento de recuperação. Para obter mais informações sobre recuperação, consulte Executando recuperação.

Todos os EnlistDurable métodos tomam um Guid objeto como seu primeiro parâmetro. O Guid é usado pelo gerenciador de transações para associar um alistamento durável a um gerenciador de recursos específico. Como tal, é imperativo que um gerente de recursos use consistentemente o mesmo Guid para se identificar, mesmo entre diferentes gerentes de recursos após a reinicialização, caso contrário, a recuperação pode falhar.

O segundo parâmetro do EnlistDurable método é uma referência ao objeto que o gerenciador de recursos implementa para receber notificações de transação. A sobrecarga usada informa ao gestor de transações se o gestor de recursos suporta a otimização SPC (Single Phase Commit). Na maioria das vezes, implementarias a interface IEnlistmentNotification para participar no Two-Phase Commit (2PC). No entanto, se quiseres otimizar o processo de confirmação, considera implementar a interface ISinglePhaseNotification para SPC. Para obter mais informações sobre o SPC, consulte Cometer uma Transação no Single-Phase e Multi-Fase e Otimização com o uso de Confirmação Monofásica e Notificação Monofásica Promovível.

O terceiro parâmetro é uma EnlistmentOptions enumeração, cujo valor pode ser um None ou EnlistDuringPrepareRequired. Se o valor for definido como EnlistDuringPrepareRequired, a inscrição poderá incluir gestores de recursos adicionais ao receber a notificação de Preparação do gestor de transações. No entanto, você deve estar ciente de que esse tipo de alistamento não é elegível para a otimização de Confirmação de Fase Única.

Alistamento volátil

Os participantes que gerenciam recursos voláteis, como um cache, devem se alistar usando os EnlistVolatile métodos. Esses objetos podem não ser capazes de obter o resultado de uma transação ou recuperar o estado de qualquer transação em que participem após uma falha do sistema.

Como dito anteriormente, um gerente de recursos faria um alistamento volátil se gerenciasse um recurso volátil na memória. Um dos benefícios do uso EnlistVolatile é que ele não força um escalonamento desnecessário da transação. Para obter mais informações sobre escalonamento de transações, consulte o tópico Escalonamento de gerenciamento de transações . A volatilidade do alistamento implica tanto uma diferença na forma como o alistamento é tratado pelo gestor de transações, como o que é esperado do gestor de recursos pelo gestor de transações. Isso ocorre porque um gerenciador de recursos voláteis não executa a recuperação. Os métodos EnlistVolatile não usam um Guid parâmetro, porque um gestor de recursos voláteis não executa a recuperação e não chamaria o método Reenlist que precisa de um Guid.

Assim como acontece com alistamentos duráveis, qualquer método de sobrecarga usado para recrutar indica ao gerenciador de transações se o gerenciador de recursos oferece suporte à otimização de confirmação monofásica. Como um gestor de recursos volátil não pode realizar recuperação, não se escreve qualquer informação de recuperação para um alistamento volátil durante a fase Preparar. Portanto, chamar o método RecoveryInformation resulta em um InvalidOperationException.

O exemplo a seguir mostra como inscrever tal objeto como um participante em uma transação usando o EnlistVolatile método.

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

Otimizando o desempenho

A Transaction classe também fornece o EnlistPromotableSinglePhase método para inscrever um Alistamento Promovível de Fase Única (PSPE). Isso permite que um gerenciador de recursos duráveis (RM) hospede e "possua" uma transação que pode ser escalada posteriormente para ser gerenciada pelo MSDTC, se necessário. Para obter mais informações sobre isso, consulte Otimização usando confirmação monofásica e Notificação monofásica promocional.

Ver também