Share via


Commit di una transazione in monofase e multifase

Ogni risorsa utilizzata in una transazione viene gestita da un gestore di risorse (in seguito indicato con la sigla GR), le cui azioni vengono coordinate da un gestore transazioni (in seguito indicato con la sigla GT). Nell'argomento Integrazione di risorse come partecipanti a una transazione viene descritto come integrare una o più risorse in una transazione. Questo argomento descrive invece come coordinare il commit di una transazione fra le risorse integrate.

Al termine della transazione, l'applicazione richiede che venga eseguito il commit o il rollback della transazione. Il gestore transazioni deve eliminare qualsiasi possibilità che si verifichino situazioni di incoerenza, come ad esempio nel caso di una transazione per cui alcuni gestori di risorse votano a favore del commit mentre altri votano a favore del rollback.

Se la transazione utilizzata coinvolge più di una risorsa, è necessario eseguire un commit 2PC (2-Phase Commit, commit a due fasi). Il protocollo 2PC, che prevede una fase di preparazione e una fase di commit, garantisce che al termine della transazione venga eseguito coerentemente il commit oppure il rollback di tutte le modifiche apportate alle risorse. Tutti i partecipanti vengono quindi informati in merito al risultato finale. Per informazioni dettagliate sul protocollo 2PC, consultare il libro sui concetti e sulle tecniche di elaborazione delle transazioni scritto da Jim Gray e appartenente alla collana Morgan Kaufmann sui sistemi di gestione dei dati (ISBN:1558601902).

Le prestazioni delle transazioni possono anche essere ottimizzate tramite il protocollo di commit monofase. Per ulteriori informazioni, vedere Ottimizzazione mediante commit monofase e notifica monofase promuovibile.

Se si desidera soltanto ricevere informazioni sul risultato di una transazione senza partecipare alla votazione, è necessario essere registrati all'evento TransactionCompleted.

Protocollo 2PC

Nella prima fase della transazione, il gestore transazioni esegue una query su ogni risorsa allo scopo di determinare se eseguire il commit o il rollback di una transazione. Nella seconda fase della transazione, il gestore transazioni informa ogni risorsa in merito al risultato delle query eseguite, consentendo l'esecuzione delle operazioni di pulitura eventualmente necessarie.

Per poter partecipare a questo tipo di transazione, un gestore di risorse deve implementare l'interfaccia IEnlistmentNotification, che fornisce i metodi chiamati dal GT per l'invio delle notifiche durante un commit 2PC. Di seguito è riportato un esempio di questa implementazione.

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

Fase di preparazione (fase 1)

Quando riceve dall'applicazione una richiesta di commit tramite una chiamata al metodo Commit, il gestore transazioni avvia la fase di preparazione di tutti i partecipanti integrati. A tale scopo, chiama il metodo Prepare su ogni risorsa integrata al fine di determinare per ognuna di esse il voto espresso in merito alla transazione.

Come illustrato nel semplice esempio seguente, il gestore di risorse che implementa l'interfaccia IEnlistmentNotification deve prima implementare il metodo Prepare.

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 il gestore di risorse durevole riceve questa chiamata, deve registrare le informazioni per il ripristino della transazione (disponibili tramite il recupero della proprietà RecoveryInformation) nonché qualsiasi informazione necessaria al completamento della transazione in caso di commit. Non è necessario eseguire questa operazione all'interno del metodo Prepare, in quanto il GR può eseguirla mediante un thread di lavoro.

Dopo aver completato la fase di preparazione, il GR deve votare il commit o il rollback della transazione chiamando rispettivamente il metodo Prepared o il metodo ForceRollback. Si noti che la classe PreparingEnlistment eredita un metodo Done dalla classe Enlistment. Se si chiama questo metodo sul callback PreparingEnlistment durante la fase di preparazione, il GT riceve una notifica in cui si indica che l'integrazione è di sola lettura (ovvero, i gestori di risorse possono leggere ma non aggiornare i dati protetti dalle transazioni) e il GT non informa più il GR in merito al risultato della transazione nella fase 2.

L'applicazione riceve informazioni sull'esito positivo del commit della transazione dopo che tutti i gestori di risorse votano tramite il metodo Prepared.

Fase di commit (fase 2)

Nella seconda fase della transazione, se tutti i GR inviano al GT una conferma di esito positivo relativamente alla fase 1, ovvero se tutti i GR hanno richiamato il metodo Prepared al termine della fase di preparazione, il GT richiama il metodo Commit per ogni gestore di risorse. I gestori di risorse possono quindi rendere definitive le modifiche e completare il commit.

Se almeno uno dei gestori di risorse invia una conferma di esito negativo relativamente alla fase 1, il gestore transazioni richiama il metodo Rollback per ogni gestore di risorse e segnala all'applicazione la non riuscita del commit.

Ne consegue che il gestore di risorse deve implementare i metodi seguenti.

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

Il GR deve eseguire tutte le operazioni necessarie per completare la transazione in base al tipo di notifica e quindi informare il GT in merito chiamando il metodo Done sul parametro Enlistment. Queste operazioni possono essere eseguite su un thread di lavoro. Si noti che nella fase 2 le notifiche possono presentarsi inline nello stesso thread che ha chiamato il metodo Prepared nella fase 1. Ne consegue che dopo la chiamata al metodo Prepared non occorre eseguire alcuna operazione (ad esempio il rilascio dei blocchi) che si prevede sia stata completata prima di ricevere le notifiche della fase 2.

Implementazione di InDoubt

Infine, è necessario implementare il metodo InDoubt per il gestore di risorse volatile. Questo metodo viene chiamato se il gestore transazioni perde il contatto con uno o più partecipanti, il cui stato risulta pertanto sconosciuto. In questo caso è necessario registrare questo problema in modo che in un secondo momento sia possibile verificare se uno o più partecipanti della transazione sono rimasti in uno stato incoerente.

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

Ottimizzazione mediante commit monofase

Il protocollo di commit monofase è più efficiente in fase di esecuzione, poiché tutti gli aggiornamenti vengono eseguiti senza alcuna coordinazione esplicita. Per ulteriori informazioni in merito, vedere Ottimizzazione mediante commit monofase e notifica monofase promuovibile.

Vedere anche

Concetti

Ottimizzazione mediante commit monofase e notifica monofase promuovibile
Integrazione di risorse come partecipanti a una transazione

Footer image

Copyright © 2007 Microsoft Corporation. Tutti i diritti riservati.