Partilhar via


Recrutando 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 Confirmando uma transação em fase única e multifásica aborda como o compromisso de 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 deseja usar o EnlistDurable método ou EnlistVolatile com base no suporte de durabilidade do seu recurso, você deve recrutar seu recurso para participar do Two Phase Commit (2PC) implementando a interface para seu IEnlistmentNotification gerenciador de recursos. Para obter mais informações sobre o 2PC, consulte Confirmando uma transação em monofásica e multifásica.

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

Alistamento durável

Os EnlistDurable métodos são usados para recrutar um gerente de recursos para participação na transação como um recurso durável. Espera-se que, se um gerenciador de recursos duráveis for derrubado no meio de uma transação, ele possa executar a recuperação uma vez que seja colocado on-line novamente, inscrevendo-se novamente (usando o método) em todas as transações nas quais foi participante e não concluiu a fase 2, e chamar RecoveryComplete assim que concluir o Reenlist 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 gerenciador de transações se o gerenciador de recursos oferece suporte à otimização SPC (Single Phase Commit). Na maioria das vezes, você implementaria a IEnlistmentNotification interface para participar do Two-Phase Commit (2PC). No entanto, se você quiser otimizar o processo de confirmação, considere a implementação da interface para o ISinglePhaseNotification SPC. Para obter mais informações sobre o SPC, consulte Confirmando uma transação em monofásica e multifásica e Otimização usando confirmação monofásica e notificação monofásica promocional.

O terceiro parâmetro é uma EnlistmentOptions enumeração, cujo valor pode ser um None ou EnlistDuringPrepareRequired. Se o valor for definido como EnlistDuringPrepareRequired, o alistamento poderá recrutar gerentes de recursos adicionais ao receber a notificação Preparar do gerenciador 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 EnlistVolatile métodos não usam um Guid parâmetro, porque um gerenciador de recursos voláteis não executa a recuperação e não chamaria o Reenlist método que precisa de um Guidarquivo .

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 gerenciador de recursos voláteis não pode executar a recuperação, nenhuma informação de recuperação é gravada para um alistamento volátil durante a fase Preparar. Portanto, chamar o RecoveryInformation método resulta em um InvalidOperationExceptionarquivo .

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 recrutar um alistamento monofásico promocional (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.

Consulte também