Partilhar via


Confirmando uma transação em monofásica e multifásica

Cada recurso usado em uma transação é gerenciado por um gerenciador de recursos (RM), cujas ações são coordenadas por um gerente de transações (TM). O tópico Recrutando recursos como participantes em uma transação discute como um recurso (ou vários recursos) pode ser inscrito em uma transação. Este tópico discute como o compromisso de transação pode ser coordenado entre os recursos alistados.

No final da transação, o aplicativo solicita que a transação seja confirmada ou revertida. O gerente de transações deve eliminar riscos, como alguns gerentes de recursos votando para se comprometer enquanto outros votam para reverter a transação.

Se sua transação envolver mais de um recurso, você deverá executar uma confirmação em duas fases (2PC). O protocolo de confirmação de duas fases (a fase de preparação e a fase de confirmação) garante que, quando a transação terminar, todas as alterações em todos os recursos sejam totalmente comprometidas ou totalmente revertidas. Todos os participantes são então informados do resultado final. Para uma discussão detalhada do protocolo de confirmação em duas fases, consulte o livro "Transaction Processing: Concepts and Techniques (Morgan Kaufmann Series in Data Management Systems) ISBN:1558601902" de Jim Gray.

Você também pode otimizar o desempenho da sua transação participando do protocolo Single Phase Commit. Para obter mais informações, consulte Otimização usando confirmação monofásica e Notificação monofásica promocional.

Se quiser apenas ser informado do resultado de uma transação e não quiser participar na votação, deve registar-se no TransactionCompleted evento.

Confirmação bifásica (2PC)

Na primeira fase de transação, o gerenciador de transações consulta cada recurso para determinar se uma transação deve ser confirmada ou revertida. Na segunda fase de transação, o gerenciador de transações notifica cada recurso sobre o resultado de suas consultas, permitindo que ele execute qualquer limpeza necessária.

Para participar desse tipo de transação, um gerente de recursos deve implementar a IEnlistmentNotification interface, que fornece métodos que são chamados pelo TM como notificações durante um 2PC. O exemplo a seguir mostra um exemplo dessa implementação.

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 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

Fase de preparação (Fase 1)

Ao receber uma Commit solicitação do aplicativo, o gerente de transações inicia a fase Preparar de todos os participantes alistados, chamando o Prepare método em cada recurso alistado, a fim de obter o voto de cada recurso na transação.

Seu gerenciador de recursos que implementa a IEnlistmentNotification interface deve primeiro implementar o método, Prepare(PreparingEnlistment) como mostra o exemplo simples a seguir.

public void Prepare(PreparingEnlistment preparingEnlistment)  
{  
     Console.WriteLine("Prepare notification received");  
     //Perform work  
  
     Console.Write("reply with prepared? [Y|N] ");  
     c = Console.ReadKey();  
     Console.WriteLine();  
  
     //If work finished correctly, reply with prepared  
     if ((c.KeyChar == 'Y') || (c.KeyChar == 'y'))  
     {  
          preparingEnlistment.Prepared();  
          break;  
     }  
  
     // otherwise, do a ForceRollback  
     else if ((c.KeyChar == 'N') || (c.KeyChar == 'n'))  
     {  
          preparingEnlistment.ForceRollback();  
          break;  
     }  
}  

Quando o gerenciador de recursos duráveis recebe essa chamada, ele deve registrar as informações de recuperação da transação (disponíveis recuperando a RecoveryInformation propriedade) e quaisquer informações necessárias para concluir a transação na confirmação. Isso não precisa ser executado dentro do Prepare método porque o RM pode fazer isso em um thread de trabalho.

Quando o RM terminar seu trabalho de preparação, ele deve votar para confirmar ou reverter chamando o Prepared método ou ForceRollback . Observe que a PreparingEnlistment classe herda um Done método da Enlistment classe. Se você chamar esse método no retorno de PreparingEnlistment chamada durante a fase Preparar, ele informará ao TM que é um alistamento Somente Leitura (ou seja, gerentes de recursos que podem ler, mas não podem atualizar dados protegidos por transações) e o RM não receberá mais notificações do gerenciador de transações quanto ao resultado da transação na fase 2.

O aplicativo é informado do compromisso bem-sucedido da transação depois que todos os gerentes de recursos votam Prepared.

Fase de confirmação (Fase 2)

Na segunda fase da transação, se o gerenciador de transações receber preparações bem-sucedidas de todos os gerentes de recursos (todos os gerentes de recursos invocaram Prepared no final da fase 1), ele invocará o Commit método para cada gerente de recursos. Os gerentes de recursos podem, então, tornar as alterações duráveis e concluir a confirmação.

Se algum gerente de recursos relatar uma falha na preparação na fase 1, o gerenciador de transações invocará o Rollback método para cada gerente de recursos e indicará a falha da confirmação para o aplicativo.

Assim, seu gerente de recursos deve implementar os seguintes métodos.

public void Commit (Enlistment enlistment)  
{  
     // Do any work necessary when commit notification is received  
  
     // Declare done on the enlistment  
     enlistment.Done();  
}  
  
public void Rollback (Enlistment enlistment)  
{  
     // Do any work necessary when rollback notification is received  
  
     // Declare done on the enlistment
     enlistment.Done();
}  

O RM deve executar qualquer trabalho necessário para concluir a transação com base no tipo de notificação e informar o TM que terminou chamando Done o Enlistment método no parâmetro. Esse trabalho pode ser feito em um thread de trabalho. Observe que as notificações da fase 2 podem acontecer embutidas no mesmo thread que chamou o Prepared método na fase 1. Como tal, você não deve fazer nenhum trabalho após a Prepared chamada (por exemplo, liberar bloqueios) que você esperaria ter concluído antes de receber as notificações da fase 2.

Implementando o InDoubt

Finalmente, você deve implementar o InDoubt método para o gerenciador de recursos voláteis. Esse método é chamado se o gerente de transações perder contato com um ou mais participantes, portanto, seu status é desconhecido. Se isso ocorrer, você deve registrar esse fato para que possa investigar mais tarde se algum dos participantes da transação foi deixado em um estado inconsistente.

public void InDoubt (Enlistment enlistment)  
{  
     // log this  
     enlistment.Done();  
}  

Otimização de confirmação monofásica

O protocolo Single Phase Commit é mais eficiente em tempo de execução porque todas as atualizações são feitas sem qualquer coordenação explícita. Para obter mais informações sobre esse protocolo, consulte Otimização usando confirmação monofásica e Notificação monofásica promocional.

Consulte também