Transazioni in .net


144

Quali sono le migliori pratiche per eseguire transazioni in C # .Net 2.0. Quali sono le classi che dovrebbero essere utilizzate? Quali sono le insidie ​​da cercare, ecc. Tutto ciò che commette e ripristina le cose. Sto appena iniziando un progetto in cui potrei dover fare alcune transazioni mentre inserisco i dati nel DB. Eventuali risposte o collegamenti anche su elementi di base relativi alle transazioni sono i benvenuti.


Ecco un buon esempio di Transazioni in .NET su codeproject da utilizzare come inizio.
Mitchel Sellers,

Risposte:


271

Esistono 2 tipi principali di transazioni; transazioni di connessione e transazioni ambientali. Una transazione di connessione (come SqlTransaction) è collegata direttamente alla connessione db (come SqlConnection), il che significa che devi continuare a passare la connessione in giro - OK in alcuni casi, ma non consente "crea / usa / rilascia" utilizzo e non consente il lavoro cross-db. Un esempio (formattato per lo spazio):

using (IDbTransaction tran = conn.BeginTransaction()) {
    try {
        // your code
        tran.Commit();
    }  catch {
        tran.Rollback();
        throw;
    }
}

Non troppo disordinato, ma limitato alla nostra connessione "conn". Se vogliamo chiamare diversi metodi, ora dobbiamo passare "conn" in giro.

L'alternativa è una transazione ambientale; nuovo in .NET 2.0, l' oggetto TransactionScope (System.Transactions.dll) consente l'utilizzo in una serie di operazioni (i provider adatti verranno automaticamente inclusi nella transazione ambientale). Ciò consente di adattarsi facilmente al codice esistente (non transazionale) e di parlare con più provider (anche se DTC verrà coinvolto se si parla con più di uno).

Per esempio:

using(TransactionScope tran = new TransactionScope()) {
    CallAMethodThatDoesSomeWork();
    CallAMethodThatDoesSomeMoreWork();
    tran.Complete();
}

Nota qui che i due metodi possono gestire le proprie connessioni (open / use / close / dispose), ma entreranno silenziosamente a far parte della transazione ambientale senza che dobbiamo passare nulla.

Se i tuoi errori di codice, Dispose () verrà chiamato senza Complete (), quindi verrà eseguito il rollback. L'annidamento previsto ecc è supportato, sebbene non sia possibile ripristinare una transazione interna ma completare la transazione esterna: se qualcuno non è soddisfatto, la transazione viene interrotta.

L'altro vantaggio di TransactionScope è che non è legato solo ai database; qualsiasi fornitore consapevole delle transazioni può utilizzarlo. WCF, per esempio. Oppure ci sono anche alcuni modelli di oggetti compatibili con TransactionScope (ad esempio classi .NET con funzionalità di rollback - forse più facile di un ricordo, anche se non ho mai usato questo approccio da solo).

Tutto sommato, un oggetto molto, molto utile.

Alcuni avvertimenti:

  • Su SQL Server 2000, TransactionScope passerà immediatamente a DTC; questo è stato risolto in SQL Server 2005 e versioni successive, può utilizzare LTM (molto meno overhead) fino a quando non si parla con 2 origini ecc., quando viene elevato a DTC.
  • C'è un problema tecnico che significa che potrebbe essere necessario modificare la stringa di connessione

CSLA .NET 2.0 supporta l'oggetto TransactionScope!
Binoj Antony,

Il problema qui è quando hai una transazione nel primo metodo e questo metodo (incapsulamento) non sa se verrà chiamato da una transazione principale o meno.
Eduardo Molteni,

1
@Eduardo - questo non è un problema quando si utilizza TransactionScope, rendendolo molto attraente. Tali transazioni nidificano e solo le commit più esterne.
Marc Gravell

Spero che tu stia ancora ascoltando. Hai detto che esistono "alcuni modelli di oggetti compatibili con TransactionScope". Puoi indicarmi alcuni di loro? Grazie.
majkinetor,

1
Ancora una volta Marc, un'altra eccellente spiegazione. Quando si dice "l'annidamento previsto è supportato" è quello per i blocchi di transazione definiti all'interno dei metodi (CallAMethodThatDoesSomeWork () ad esempio) stessi? O con il ambito di transazione definito all'esterno, non è richiesto?
Phil Cooper,

11
protected void Button1_Click(object sender, EventArgs e)
   {


       using (SqlConnection connection1 = new SqlConnection("Data Source=.\\SQLEXPRESS;AttachDbFilename=|DataDirectory|\\Database.mdf;Integrated Security=True;User Instance=True"))
       {
           connection1.Open();

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

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

           try
           {
               // Execute two separate commands.
               command.CommandText =
                "insert into [doctor](drname,drspecialization,drday) values ('a','b','c')";
               command.ExecuteNonQuery();
               command.CommandText =
                "insert into [doctor](drname,drspecialization,drday) values ('x','y','z')";
               command.ExecuteNonQuery();

               // Commit the transaction.
               sqlTran.Commit();
               Label3.Text = "Both records were written to database.";
           }
           catch (Exception ex)
           {
               // Handle the exception if the transaction fails to commit.
               Label4.Text = 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.
                   Label5.Text = exRollback.Message;

               }
           }
       }


   }

4

È inoltre possibile concludere la transazione nella propria procedura memorizzata e gestirla in questo modo invece di eseguire transazioni in C # stesso.


1

se ne hai solo bisogno per cose relative a db, alcuni Mapper OR (ad esempio NHibernate) supportano i transactinos fuori dalla scatola per impostazione predefinita.


0

Dipende anche da cosa ti serve. Per le transazioni SQL di base potresti provare a fare transazioni TSQL usando BEGIN TRANS e COMMIT TRANS nel tuo codice. Questo è il modo più semplice ma ha complessità e devi stare attento a impegnarti correttamente (e rollback).

Vorrei usare qualcosa di simile

SQLTransaction trans = null;
using(trans = new SqlTransaction)
{
    ...
    Do SQL stuff here passing my trans into my various SQL executers
    ...
    trans.Commit  // May not be quite right
}

Qualsiasi errore ti farà uscire immediatamente usinge la transazione eseguirà sempre il commit o il rollback (a seconda di ciò che gli dici di fare). Il problema più grande che abbiamo dovuto affrontare era assicurarci che fosse sempre commesso. L'utilizzo garantisce che l'ambito della transazione sia limitato.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.