Confirmar uma transação de fase única e de várias fases

Cada recurso usado em uma transação é gerenciado por um Gerenciador de recursos (RM), as ações são coordenadas por um Gerenciador de transações (TM). O tópico Como inscrever recursos como participantes em uma transação aborda como um recurso (ou vários recursos) pode ser alistado em uma transação. Este tópico discute como confirmação de transação pode ser coordenada entre recursos.

No final da transação, o aplicativo solicita que a transação seja confirmada ou revertida. O Gerenciador de transações deve eliminar riscos, como alguns gerenciadores de recursos de votação para confirmar quando outro votação para reverter a transação.

Se a transação envolve mais de um recurso, você deve realizar uma confirmação de 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 termina, todas as alterações a todos os recursos são totalmente confirmadas ou revertidas completamente. Todos os participantes, em seguida, são informados do resultado final. Para obter uma discussão detalhada sobre o protocolo de confirmação de duas fases, consulte o livro "Transaction Processing: Concepts and Techniques [Processamento de transações: conceitos e técnicas] (Série de Morgan Kaufmann sobre sistemas de gerenciamento de dados) ISBN:1558601902" de Jim Gray.

Você também pode otimizar o desempenho da transação que fazem parte do protocolo de confirmação de fase única. Para obter mais informações, confira Otimização usando a confirmação de fase única e a notificação de fase única passível de promoção.

Se você apenas deseja ser informado do resultado da transação e não quiser participar de votação, você deve se registrar para o TransactionCompleted eventos.

Confirmação de duas fases (2PC)

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

Para participar desse tipo de transação, um Gerenciador de recursos deve implementar o 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

Preparar fase (fase 1)

Ao receber um Commit solicitação do aplicativo, o Gerenciador de transações começa a fase de preparação de todos os participantes inscrita chamando o Prepare método em cada inscrito recurso, para obter um voto de cada recurso na transação.

O Gerenciador de recursos que implementa o IEnlistmentNotification primeiro deve implementar a interface a Prepare(PreparingEnlistment) método como mostra o seguinte exemplo simples.

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 deverá registrar informações de recuperação da transação (disponível ao recuperar o RecoveryInformation propriedade) e qualquer informação é necessária para concluir a transação de confirmação. Isso não precisa ser executada dentro do Prepare método porque o Gerenciador de recursos pode fazer isso em um thread de trabalho.

Quando o RM terminou seu trabalho de preparação, devem votar para confirmar ou reverter chamando o Prepared ou ForceRollback método. Observe que o PreparingEnlistment classe herda um Done método a partir de Enlistment classe. Se você chamar esse método no PreparingEnlistment o retorno de chamada durante a fase de preparação, ele informa o TM que é uma inscrição de somente leitura (ou seja, gerenciadores de recursos que pode ler, mas não é possível atualizar dados protegidos por transação) e o RM não recebe nenhuma notificação adicional do Gerenciador de transações sobre o resultado da transação na fase 2.

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

Confirmar fase (fase 2)

Na segunda fase da transação, se o Gerenciador de transações recebe bem-sucedida prepara de todos os gerenciadores de recursos (todos os gerenciadores de recursos invocado Prepared no final da fase 1), ele invoca o Commit método para cada Gerenciador de recursos. Os gerenciadores de recursos, faça as alterações durável e concluir a confirmação.

Se o Gerenciador de recursos relatou uma falha ao preparar na fase 1, o Gerenciador de transações invoca o Rollback método para cada Gerenciador de recursos e indica a falha da confirmação ao aplicativo.

Assim, o Gerenciador de recursos deve implementar os métodos a seguir.

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 Gerenciador de recursos deve executar qualquer trabalho necessário para concluir a transação com base no tipo de notificação e informar o TM concluiu chamando Done método o Enlistment parâmetro. Esse trabalho pode ser feito em um thread de trabalho. Observe que as notificações de fase 2 podem acontecer embutido no mesmo thread que chamou o Prepared método na fase 1. Assim, você não deve fazer qualquer trabalho após o Prepared chamada (por exemplo, liberar bloqueios) que você esperaria ter concluído antes de receber as notificações de fase 2.

Implementando incertas

Por fim, você deve implementar o InDoubt método para o Gerenciador de recursos volátil. Esse método é chamado se o Gerenciador de transações perder o contato com um ou mais participantes, portanto, seu status é desconhecido. Se isso ocorrer, você deve registrar esse fato para que você possa investigar mais tarde se qualquer um 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 de fase única

O protocolo de confirmação de fase única é 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, confira Otimização usando a confirmação de fase única e a notificação de fase única passível de promoção.

Confira também