Confirmar una transacción en fase única y múltiple

Un administrador de recursos (RM) administra cada recurso utilizado, cuyas acciones coordina un administrador de transacciones (TM). En el tema Alistamiento de recursos como participantes en una transacción se explica cómo se puede alistar un recurso (o varios recursos) en una transacción. En este tema se trata cómo la confirmación de la transacción se puede coordinar entre los recursos inscritos.

Al final de la transacción, la aplicación solicita que se confirme o se revierta la transacción. El administrador de transacciones debe eliminar los riesgos como algunos administradores de recursos que votan para confirmar mientras que otros votan para deshacer la transacción.

Si su transacción implica más de un recurso, debe realizar una confirmación en dos fases (2PC). El protocolo de confirmación en dos fases (la fase de preparación y la de confirmación) asegura que cuando la transacción finaliza, todos los cambios a todos los recursos se confirman o se deshacen. Todos los participantes se informan a continuación del resultado final. Para obtener una discusión detallada del protocolo de confirmación en dos fases, consulta el libro «Procesamiento de transacciones: Conceptos y Técnicas (Serie de Morgan Kaufmann en Sistemas de administración de datos) ISBN:1558601902» por Jim Gray.

También puede optimizar el rendimiento de su transacción tomando parte en el protocolo de confirmación de fase única. Para más información, consulta Optimización mediante confirmación de fase única y notificación de fase única promocionable.

Si solo desea ser informado del resultado de una transacción, y no desea participar para votar, se debería registrar para el evento TransactionCompleted.

Confirmación en dos fases (2PC)

En la primera fase de la transacción, el administrador de transacciones consulta cada recurso para determinar si una transacción se debería confirmar o deshacer. En la segunda fase de la transacción, el administrador de transacciones notifica a cada recurso el resultado de sus consultas, permitiéndole realizar cualquier limpieza necesaria.

Para participar en este tipo de transacción, un administrador de recursos debe implementar la interfaz IEnlistmentNotification, que proporciona métodos que el TM llamará como notificaciones durante una 2PC. En el siguiente ejemplo se muestra un ejemplo de dicha implementación.

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 la fase (fase 1)

Al recibir una solicitud Commit de la aplicación, el administrador de transacciones comienza la fase de preparación de todos los participantes alistados llamando al método Prepare en cada recurso alistado para obtener el voto de cada recurso en la transacción.

Su administrador de recursos que implementa la interfaz IEnlistmentNotification debería implementar primero el método Prepare(PreparingEnlistment) como las presentaciones del ejemplo simples siguientes.

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

Cuando el administrador de recursos duradero recibe esta llamada, debería registrar la información de la recuperación (disponible recuperando la propiedad RecoveryInformation ) de la transacción y cualquier información es necesaria para completar la transacción de confirmación. Esto no necesita ser realizado dentro del método Prepare porque RM puede hacer esto en un subproceso de trabajo.

Cuando RM ha finalizado su trabajo de preparación, debería votar para confirmar o deshacer llamando aPrepared o al método ForceRollback. Observe que la clase PreparingEnlistment hereda un método Done de la clase Enlistment. Si llama a este método en la devolución de llamada PreparingEnlistment durante la fase de preparación, éste informa al TM de que es una inscripción de solo lectura (es decir, administradores de recursos que pueden leer pero no pueden actualizar los datos protegidos por transacción) y el RM no recibe ninguna notificación más extensa del administrador de transacciones acerca del resultado de la transacción en fase 2.

Se cuenta en la aplicación la exitosa confirmación de la transacción después de que todos los administradores de recursos voten Prepared.

Confirmar la fase (fase 2)

En la segunda fase de la transacción, si el administrador de transacciones recibe correcta preparación de todos los administradores de recursos (todos los administradores de recursos han invocado Prepared al final de fase 1), invoca el método Commit para cada administrador de recursos. Los administradores de recursos pueden realizar a continuación los cambios duraderos y completar la confirmación.

Si cualquier administrador de recursos informa de un error para preparar en fase 1, el administrador de transacciones invoca el método Rollback para cada administrador de recursos e indica el error de la confirmación a la aplicación.

Así, su administrador de recursos debería implementar los métodos siguientes.

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();
}  

El administrador de recursos realizará las operaciones necesarias para finalizar la transacción basada en el tipo de notificación y después informará al administrador de transacciones de que ha finalizado llamando al método Done en el parámetro Enlistment. Este trabajo se puede hacer en un subproceso de trabajo. Tenga en cuenta que las notificaciones de la fase 2 pueden suceder alineadas en el mismo subproceso que llamó al método Prepared en la fase 1. Como tal, no debería realizar ningún trabajo después de la llamada a Prepared (por ejemplo, liberando bloqueos) que debería esperar que se habrían completado antes de recibir las notificaciones de la fase 2.

Implementar InDoubt

Finalmente, debería implementar el método InDoubt para el administrador de recursos volátil. Se llama a este método si el administrador de transacciones pierde el contacto con uno o más participantes, por lo que su estado es desconocido. Si esto se produce, debería registrar este hecho para que se pueda investigar después si cualquiera de los participantes de la transacción ha quedado en un estado incoherente.

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

Optimización de confirmación de fase única

La fase única el protocolo de confirmación es más eficaz en el tiempo de ejecución porque todas las actualizaciones se hacen sin ninguna coordinación explícita. Para más información sobre este protocolo, consulta Optimización mediante confirmación de fase única y notificación de fase única promocionable.

Consulte también