Inscrever recursos como participantes em uma transação

Cada recurso que participa de uma transação é gerenciado por um Gerenciador de recursos, as ações são coordenadas por um Gerenciador de transações. A coordenação é feita por meio de notificações para assinantes que tem se inscrito em uma transação por meio do Gerenciador de transações.

Este tópico aborda como um recurso (ou vários recursos) podem ser inscrita em uma transação, bem como os diferentes tipos de inscrição. O tópico Committing a Transaction in Single-Phase e Multi-Phase aborda como o compromisso de transação pode ser coordenado entre os recursos inscritos.

Recursos de inscrição em uma transação

Em ordem para um recurso para participar de uma transação, ele deve se inscrever na transação. A classe define um conjunto de métodos cujos nomes começam Transaction com Enlist que fornecem essa funcionalidade. Os diferentes métodos de inscrever correspondem aos diferentes tipos de inscrições que um gerenciador de recursos pode ter. Especificamente, você usa o EnlistVolatile métodos para recursos voláteis e o EnlistDurable método Recursos duráveis. A durabilidade (ou o inverso a volatilidade) de um recurso Gerenciador refere-se ao Gerenciador de recursos oferece suporte a recuperação de falhas. Se um Gerenciador de recursos oferece suporte à recuperação de falha, ele persiste os dados para o armazenamento durável durante da Fase1 (preparar), de modo que, se o Gerenciador de recursos de ficar inativo, ele pode novamente se inscrever na transação após a recuperação e executar as ações apropriadas com base em notificações recebidas de TM. Em geral, os gerenciadores de recursos voláteis gerenciar recursos voláteis, como uma estrutura de dados na memória (por exemplo, na memória transacionado-hashtable) e gerenciadores de recursos duráveis gerenciar recursos em um repositório de backup mais persistente (por exemplo, um banco de dados cujo armazenamento de backup em disco).

Para simplificar, depois de decidir se deseja usar o EnlistDurable ou EnlistVolatile método com base no suporte a durabilidade do recurso, você deve inscrever o recurso para participar de dois a fase de confirmação (2PC), Implementando o IEnlistmentNotification interface para seu Gerenciador de recursos. Para obter mais informações sobre 2PC, consulte Committing a Transaction in Single-Phase and Multi-Phase.

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

Distribuição durável

O EnlistDurable métodos são usados para inscrever um Gerenciador de recursos de participação na transação como um recurso durável. Espera-se que se um Gerenciador de recursos durável é interrompido no meio de uma transação, ele pode realizar recuperação depois que ele é colocado online pelo reenlisting (usando o Reenlist método) em todas as transações em que ele foi um participante e não concluiu a fase 2 e chamar RecoveryComplete depois que ele termine o processamento de recuperação. Para obter mais informações sobre recuperação, consulte Executando a recuperação.

O EnlistDurable métodos usam um Guid objeto como seu primeiro parâmetro. O Guid é usado pelo Gerenciador de transações para associar uma distribuição durável com um Gerenciador de recursos específico. Como tal, é imperativo que um Gerenciador de recursos consistentemente usa o mesmo Guid para identificar em si mesmo entre diferentes gerentes de recursos após a reinicialização, caso contrário, a recuperação poderá falhar.

O segundo parâmetro do EnlistDurable método é uma referência ao objeto que implementa o Gerenciador de recursos para receber notificações de transação. A sobrecarga que é usar informa o Gerenciador de transações se seu Gerenciador de recursos oferece suporte a otimização de confirmação de fase única (SPC). Na maioria das vezes você implementaria o IEnlistmentNotification interface para fazer parte de protocolo 2PC (2PC). No entanto, se você deseja otimizar o processo de confirmação, você pode considerar a implementação de ISinglePhaseNotification interface para SPC. Para obter mais informações sobre o SPC, consulte Committing a Transaction in Single-Phase and Multi-Phase and Optimization using Single Phase Commit and Promotable Single Phase Notification.

O terceiro parâmetro é um EnlistmentOptions enumeração, cujo valor pode ser None ou EnlistDuringPrepareRequired. Se o valor for definido como EnlistDuringPrepareRequired, a inscrição pode inscrever gerenciadores de recursos adicionais depois de receber a notificação de preparação do Gerenciador de transações. No entanto, você deve estar ciente de que esse tipo de inscrição não está qualificado para a otimização de confirmação de fase única.

Inscrição volátil

Participantes do gerenciamento de recursos voláteis, como um cache deve inscrever usando o EnlistVolatile métodos. Esses objetos não poderá obter o resultado de uma transação ou recuperar o estado de qualquer transação que participam após uma falha do sistema.

Conforme mencionado anteriormente, um Gerenciador de recursos se tornaria uma inscrição volátil se gerencia na memória e recursos voláteis. Um dos benefícios do uso de EnlistVolatile é que ele não forçar um escalonamento desnecessário da transação. Para obter mais informações sobre o escalonamento de transações, consulte o tópico Escalonamento de gerenciamento de transações. Inscrever-se em uma tecnologia implica uma diferença em como a inscrições é manipulada pelo gerenciador de transações, bem como o que é esperado do gerenciador de recursos pelo gerenciador de transações. Isso ocorre porque um Gerenciador de recursos volátil não executar a recuperação. O EnlistVolatile métodos não têm um Guid parâmetro, porque um Gerenciador de recursos volátil não realiza recuperação e não chama o Reenlist método que precisa de um Guid.

Assim como acontece com inscrições duráveis, independentemente do método sobrecarga que você pode usar para se inscrever indica para o Gerenciador de transações se seu Gerenciador de recursos oferece suporte a otimização de confirmação de fase única. Como um Gerenciador de recursos volátil não pode realizar a recuperação, nenhuma informação de recuperação é criada para uma inscrição volátil durante a fase de preparação. Portanto, chamar o RecoveryInformation método resulta em um InvalidOperationException.

O exemplo a seguir mostra como se 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 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();
    }
}
    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

Aperfeiçoando o desempenho

O Transaction classe também fornece o EnlistPromotableSinglePhase método para inscrever um podem ser promovidas única fase de inscrição (PSPE). Isso permite que um recurso durável manager (RM) para hospedar e "proprietário" de uma transação que posteriormente pode ser escalonada para ser gerenciado pelo MSDTC se necessário. Para obter mais informações sobre isso, consulte Otimização usando Commit de Fase Única e Notificação de Fase ÚnicaPromovendo .

Confira também