Transazioni locali

Le transazioni in ADO.NET vengono usate quando si vogliono associare più attività in modo che vengano eseguite come una singola unità di lavoro. Ad esempio, si supponga che un'applicazione esegua due attività. Ovvero che prima aggiorni una tabella con le informazioni sull'ordine e che, successivamente, aggiorni una tabella contenente le informazioni d'inventario addebitando gli articoli ordinati. Se una delle attività non viene eseguita correttamente, verrà eseguito il rollback di entrambi gli aggiornamenti.

Determinazione del tipo di transazione

Una transazione è considerata locale quando è composta da una sola fase e viene gestita direttamente dal database. Una transazione è considerata distribuita quando viene coordinata da un monitoraggio delle transazioni e usa meccanismi fail-safe (quale il commit in due fasi) per la risoluzione.

Ogni provider di dati .NET Framework ha un proprio oggetto Transaction per l'esecuzione di transazioni locali. Per eseguire una transazione in un database di SQL Server, selezionare una transazione System.Data.SqlClient. Per una transazione Oracle usare il provider System.Data.OracleClient. È anche disponibile una classe DbTransaction che consente di scrivere codice indipendente dal provider che richiede transazioni.

Nota

Le transazioni sono più efficienti quando vengono eseguite nel server. Se si usa un database SQL Server in cui sono ampiamente usate le transazioni esplicite, è consigliabile scrivere queste transazioni come stored procedure usando l'istruzione BEGIN TRANSACTION Transact-SQL.

Esecuzione di una transazione con una singola connessione

In ADO.NET è possibile controllare le transazioni con l'oggetto Connection. È possibile avviare una transazione locale con il metodo BeginTransaction. Una volta iniziata una transazione, è possibile inserire un comando nell'elenco della transazione usando la proprietà Transaction di un oggetto Command. In seguito è possibile eseguire il commit o il rollback delle modifiche apportate nell'origine dati in base all'esito corretto o errato dei componenti della transazione.

Nota

Il metodo EnlistDistributedTransaction non deve essere usato per una transazione locale.

L'ambito della transazione si limita alla connessione. Nell'esempio seguente viene eseguita una transazione esplicita composta da due comandi separati nel blocco try. I comandi eseguono le istruzioni INSERT sulla tabella Production.ScrapReason nel database di esempio SQL Server AdventureWorks e, se non vengono generate eccezioni, viene eseguito il commit. Il codice nel blocco catch esegue il rollback della transazione se viene generata un'eccezione. Allo stesso modo, se la transazione viene interrotta oppure la connessione viene chiusa prima del completamento della transazione, viene eseguito automaticamente il rollback della transazione.

Esempio

Per eseguire una transazione, usare la procedura seguente:

  1. Chiamare il metodo BeginTransaction dell'oggetto SqlConnection per contrassegnare l'inizio della transazione. Il metodo BeginTransaction restituisce un riferimento alla transazione. Questo riferimento viene assegnato agli oggetti SqlCommand contenuti nell'elenco della transazione.

  2. Assegnare l'oggetto Transaction alla proprietà Transaction dell'oggetto SqlCommand da eseguire. Se un comando viene eseguito su una connessione con una transazione attiva e l'oggetto Transaction non è stato assegnato alla proprietà Transaction dell'oggetto Command, viene generata un'eccezione.

  3. Eseguire i comandi richiesti.

  4. Chiamare il metodo Commit dell'oggetto SqlTransaction per completare la transazione oppure il metodo Rollback per interrompere la transazione. Se la connessione viene chiusa o eliminata prima che venga eseguito il metodo Commit o Rollback, viene eseguito il rollback della transazione.

Nell'esempio di codice seguente viene illustrata la logica transazionale usando ADO.NET con Microsoft SQL Server.

using (SqlConnection connection = new(connectionString))
{
    connection.Open();

    // Start a local transaction.
    SqlTransaction sqlTran = connection.BeginTransaction();

    // Enlist a command in the current transaction.
    SqlCommand command = connection.CreateCommand();
    command.Transaction = sqlTran;

    try
    {
        // Execute two separate commands.
        command.CommandText =
          "INSERT INTO Production.ScrapReason(Name) VALUES('Wrong size')";
        command.ExecuteNonQuery();
        command.CommandText =
          "INSERT INTO Production.ScrapReason(Name) VALUES('Wrong color')";
        command.ExecuteNonQuery();

        // Commit the transaction.
        sqlTran.Commit();
        Console.WriteLine("Both records were written to database.");
    }
    catch (Exception ex)
    {
        // Handle the exception if the transaction fails to commit.
        Console.WriteLine(ex.Message);

        try
        {
            // Attempt to roll back the transaction.
            sqlTran.Rollback();
        }
        catch (Exception exRollback)
        {
            // Throws an InvalidOperationException if the connection
            // is closed or the transaction has already been rolled
            // back on the server.
            Console.WriteLine(exRollback.Message);
        }
    }
}
Using connection As New SqlConnection(connectionString)
    connection.Open()

    ' Start a local transaction.
    Dim sqlTran As SqlTransaction = connection.BeginTransaction()

    ' Enlist a command in the current transaction.
    Dim command As SqlCommand = connection.CreateCommand()
    command.Transaction = sqlTran

    Try
        ' Execute two separate commands.
        command.CommandText = _
          "INSERT INTO Production.ScrapReason(Name) VALUES('Wrong size')"
        command.ExecuteNonQuery()
        command.CommandText = _
          "INSERT INTO Production.ScrapReason(Name) VALUES('Wrong color')"
        command.ExecuteNonQuery()

        ' Commit the transaction
        sqlTran.Commit()
        Console.WriteLine("Both records were written to database.")

    Catch ex As Exception
        ' Handle the exception if the transaction fails to commit.
        Console.WriteLine(ex.Message)

        Try
            ' Attempt to roll back the transaction.
            sqlTran.Rollback()

        Catch exRollback As Exception
            ' Throws an InvalidOperationException if the connection 
            ' is closed or the transaction has already been rolled 
            ' back on the server.
            Console.WriteLine(exRollback.Message)
        End Try
    End Try
End Using

Vedi anche