Transazioni
Una transazione è una sequenza di operazioni combinatesecondo una logica e che possono venir eseguite per intero oin senso contrario. Sono importanti in quanto aiutano ildatabase a soddisfare l' ogni punto dell' ACID. Letransazioni sono parte integrante dell' ADO.NET, chegarantisce appunto che un blocco di richieste venganoeseguite per intero, o che vengano eseguite al contrario. Inquesto articolo tratteremo appunto come lavorare con letransazioni in ADO.NET 1.1 e 2.0.
Implementare transazioni in ADO.NET
Le transazioni vengono richiamate tramite il metodoBeginTransaction della classe di connessione, il quale avviaun oggetto del tipo SqlTransaction. Una volta inserite leoperazioni da far svolgere alla transazione, ènecessario chiamare il metodo Commit dell' oggettoSqlTransaction o, nel caso si vogliano terminare leoperazioni, richiamare il metodo Rollback.
Ricapitolando, per lavorare con le transazioni bisognaaprire un' istanza di connessione ed una di transazione.Fatto ciò, bisogna chiamare il metodo relativo alleproprie esigenze; le transazioni sono supportate nell'ADO.NET dalla classe SqlTransaction, che appartiene alnamespace 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 inADO.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 stringSqlConnection 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 usareil comando "using". Come recita l' MSDN,"Using definisce l' ambito fuori dal quale uno opiù 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 ulteriorifeatures che migliorano nettamente l' esperienza deiprogrammatori con le transazioni. E' stato introdotto, adesempio, un nuovo namespace chiamato System.Transactions, ilquale promette migliori prestazioni nel caso di transazionidistribuite su più fronti. Al suo interno troviamo laclasse TransactionScope, che può dare il via apiù di un' istruzione. Nel momento in cui latransazione viene portata correttamente a compimento, iltutto si applica al database; in caso contrario, vieneannullato tutto. Per questo è necessario utilizzare ilmetodo TransactionScope per definire quando la transazione sipuò dire conclusa. Ecco come, quanto sopra-dettopuò 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 TransactionScopesupporta anche transazioni distribuite, ovvero l'implementazione della stessa transazione su più di undatabase. 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 ricevutodal metodo BeginTransaction alla proprietà Transactiondell' oggetto Command; inoltre, quando la prima queryverrà processata ed eseguita, l' applicazionefornirà l' InvalidOperationException; allo stessomodo, l' istanza Connection deve essere avviata chiamandoil metodo Open prima dell' avvio di una nuovatransazione; solo così l'InvalidOperationException verrà mostrato.
Tenere inoltre conto che, più corte saranno le singoletransazioni, migliori saranno le prestazioni. Per questomotivo si consiglia il loro utilizzo solamente in casi direale necessità, mentre è invece sconsigliatoabusarne.
- Articolo precedente Store procedure (Parte II)
- Articolo successivo Data paging: Paginazione dei risultati