Transazioni

Una transazione è una sequenza di operazioni combinate secondo una logica e che possono venir eseguite per intero o in senso contrario. Sono importanti in quanto aiutano il database a soddisfare l' ogni punto dell' ACID. Le transazioni sono parte integrante dell' ADO.NET, che garantisce appunto che un blocco di richieste vengano eseguite per intero, o che vengano eseguite al contrario. In questo articolo tratteremo appunto come lavorare con le transazioni in ADO.NET 1.1 e 2.0.

Implementare transazioni in ADO.NET

Le transazioni vengono richiamate tramite il metodo BeginTransaction della classe di connessione, il quale avvia un oggetto del tipo SqlTransaction. Una volta inserite le operazioni da far svolgere alla transazione, è necessario chiamare il metodo Commit dell' oggetto SqlTransaction o, nel caso si vogliano terminare le operazioni, richiamare il metodo Rollback.
Ricapitolando, per lavorare con le transazioni bisogna aprire un' istanza di connessione ed una di transazione. Fatto ciò, bisogna chiamare il metodo relativo alle proprie esigenze; le transazioni sono supportate nell' ADO.NET dalla classe SqlTransaction, che appartiene al namespace System.Data.SqlClient. Le proprietà principali di questa classe sono:

  • Connessione: indica all' SqlConnection a cosa è associata la transazione
  • IsolationLevel: specifica l' IsolationLevel della transazione

I metodi principali di tale classe sono:

  • Commit(): per iniziare la transazione;
  • RollBack(): per terminare la transazione corrente
  • Save(): per salvare un determinato momento della transazione, da richiamare in seguito per avviarne un' altra che parta dal momento del salvataggio

Ecco ora i passaggi per implementare una transazione in ADO.NET:

  • Connettersi al database
  • Creare un' istanza SqlCommand con i parametri necessari
  • Avviare la connessione al database tramite un0 istanza di connessione
  • Richiamare il metodo BeginTransaction o l' oggetto Connection per segnare l' inizio della transazione
  • Eseguire i comandi sql usando l' istanza di comando
  • Richiamare o il metodo Commit dell' oggetto Transaction per portare a termine la transazione, oppure il Rollback per cancellare o terminare la transazione
  • Chiudere la connessione al database

Ecco il codice di quanto detto a parole:

 

string connectionString = ...; //Some connection string
SqlConnection sqlConnection = new SqlConnection(connectionString);
sqlConnection.Open();

SqlTransaction sqlTransaction = sqlConnection.BeginTransaction();

SqlCommand sqlCommand = new SqlCommand();
sqlCommand.Transaction = sqlTransaction;

try
{
  sqlCommand.CommandText = "Insert into Employee (EmpCode, EmpName) VALUES (1, 'Joydip')";
  sqlCommand.ExecuteNonQuery();
  sqlCommand.CommandText = "Insert into Dept (DeptCode, DeptName, EmpCode) VALUES (9, 'Software', 1)";
  sqlCommand.ExecuteNonQuery();
  sqlTransaction.Commit();
  //Usual code
}

catch(Exception e)
{
  sqlTransaction.Rollback();
  //Usual code
}

finally
{
  sqlConnection.Close();
}

 

Nella prossima porzione di codice vedremo invece come usare il comando "using". Come recita l' MSDN, "Using definisce l' ambito fuori dal quale uno o più oggetti verranno disposti."

using (SqlConnection sqlConnection = new SqlConnection(connectionString))
{
    SqlCommand command = connection.CreateCommand();
    SqlTransaction transaction = null;
   
    try
    {
        sqlConnection.Open();
        transaction = sqlConnection.BeginTransaction();
       
        command.Transaction = transaction;
        
        command.CommandText = "Insert into employee (empID, empName) values (1, 'Joydip');
        command.ExecuteNonQuery();
       
        command.CommandText = "Insert into dept (deptID,deptName,empID) values (9,'Software',1)";
        command.ExecuteNonQuery();
       
        transaction.Commit();
    }
    catch(Exception ex)
    {
        transaction.Rollback();
        throw ex;
    }
    finally
    {
        sqlConnection.Close();
    }
}

La versione 2.0 dell' ADO.NET implementa ulteriori features che migliorano nettamente l' esperienza dei programmatori con le transazioni. E' stato introdotto, ad esempio, un nuovo namespace chiamato System.Transactions, il quale promette migliori prestazioni nel caso di transazioni distribuite su più fronti. Al suo interno troviamo la classe TransactionScope, che può dare il via a più di un' istruzione. Nel momento in cui la transazione viene portata correttamente a compimento, il tutto si applica al database; in caso contrario, viene annullato tutto. Per questo è necessario utilizzare il metodo TransactionScope per definire quando la transazione si può dire conclusa. Ecco come, quanto sopra-detto può essere applicato:

bool IsConsistent = false;
using (System.Transactions.TransactionScope transactionScope = new System.Transactions.TransactionScope())
{
      SqlConnection sqlConnection = newSqlConnection(connectionString);
      string sqlString = "Update emp set empName = 'Joydip Kanjilal' where empID = 9";
      SqlCommand cmd1 = newSqlCommand(sql, cn);
      sqlConnection.Open();
      cmd1.ExecuteNonQuery();
      sqlConnection.Close();
      transactionScope.Consistent = IsConsistent;
}

Come abbiamo già detto, la nuova TransactionScope supporta anche transazioni distribuite, ovvero l' implementazione della stessa transazione su più di un database. Ecco come:

 

using (TransactionScope transactionScope = new TransactionScope())
{
   using (SqlConnection codesDatabaseConnection = new SqlConnection(codesDatabaseConnectionString))
   {
      SqlCommand sqlCommandCodes = codesDatabaseConnection.CreateCommand();
      sqlCommandCodes.CommandText = "Insert Into codes (codeID,codeText) values (1,'Test')";
      codesDatabaseConnection.Open();
      sqlCommandCodes.ExecuteNonQuery();
      codesDatabaseConnection.Close();
   }

   using (SqlConnection statesDatabaseConnection = new SqlConnection(statesDatabaseConnectionString))
   {
      SqlCommand sqlCommandStates = statesDatabaseConnection.CreateCommand();
      sqlCommandStates.CommandText = "Insert into States(stateID,stateName) values (1, 'Test')";
      codesDatabaseConnection.Open();
      sqlCommandStates.ExecuteNonQuery();
      statesDatabaseConnection.Close();
   }

   transactionScope.Complete();
}

 

Note

Bisogna ricordare di associare l' SqlTransaction ricevuto dal metodo BeginTransaction alla proprietà Transaction dell' oggetto Command; inoltre, quando la prima query verrà processata ed eseguita, l' applicazione fornirà l' InvalidOperationException; allo stesso modo, l' istanza Connection deve essere avviata chiamando il metodo Open prima dell' avvio di una nuova transazione; solo così l' InvalidOperationException verrà mostrato.

Tenere inoltre conto che, più corte saranno le singole transazioni, migliori saranno le prestazioni. Per questo motivo si consiglia il loro utilizzo solamente in casi di reale necessità, mentre è invece sconsigliato abusarne.



Ti potrebbe interessare anche

commenta la notizia

C'è 1 commento
Pier Paolo
Condividi le tue opinioni su questo articolo!