Transaktionen in .net

Was sind die besten Vorgehensweisen für Transaktionen in C # .Net 2.0? Welche classn sollten verwendet werden? Was sind die Fallstricke, nach denen man Ausschau halten muss usw. All das Commit- und Rollback-Zeug. Ich beginne gerade ein Projekt, wo ich einige Transaktionen machen muss, während ich Daten in die database einfüge. Alle Antworten oder Links für selbst grundlegende Dinge über Transaktionen sind willkommen.

   

Es gibt 2 Hauptarten von Transaktionen; Verbindungstransaktionen und Ambient-Transaktionen. Eine Verbindungstransaktion (z. B. SqlTransaction) ist direkt an die db-Verbindung gebunden (z. B. SqlConnection), was bedeutet, dass Sie die Verbindung weiterleiten müssen – in einigen Fällen OK, aber nicht zulassen / erstellen / verwenden / freigeben Verwendung, und Cross-db-Arbeit nicht zulassen. Ein Beispiel (für Platz formatiert):

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

Nicht zu chaotisch, aber beschränkt auf unsere Verbindung “conn”. Wenn wir zu verschiedenen Methoden aufrufen wollen, müssen wir jetzt “Conn” weitergeben.

Die Alternative ist eine Ambient-Transaktion; Neu in .NET 2.0 ermöglicht das TransactionScope- Objekt (System.Transactions.dll) die Verwendung für eine Reihe von Operationen (geeignete Anbieter werden automatisch in die Ambient-Transaktion aufgenommen). Dies macht es einfach, sich in vorhandenen (nicht-transaktionalen) Code einzufügen und mit mehreren Anbietern zu kommunizieren (obwohl DTC involviert wird, wenn Sie mit mehr als einem sprechen).

Beispielsweise:

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

Beachten Sie hier, dass die beiden Methoden ihre eigenen Verbindungen verwalten können (Öffnen / Verwenden / Schließen / Entcasting), aber sie werden automatisch Teil der Ambient-Transaktion, ohne dass wir etwas übergeben müssen.

Wenn Ihre Codeerrors auftreten, wird Dispose () ohne Complete () aufgerufen, sodass es zurückgesetzt wird. Die erwartete Verschachtelung usw. wird unterstützt, obwohl Sie eine innere Transaktion nicht zurücksetzen können, ohne die äußere Transaktion abzuschließen: Wenn jemand unglücklich ist, wird die Transaktion abgebrochen.

Der andere Vorteil von TransactionScope ist, dass es nicht nur an databaseen gebunden ist. jeder transaktionsbewusste Anbieter kann es verwenden. WCF zum Beispiel. Oder es gibt sogar einige TransactionScope-kompatible Objektmodelle (dh .NET-classn mit Rollback-function – vielleicht einfacher als ein Memento, obwohl ich diesen Ansatz nie selbst benutzt habe).

Alles in allem ein sehr, sehr nützliches Objekt.

Einige Vorbehalte:

  • Auf SQL Server 2000 wird ein TransactionScope sofort zu DTC wechseln; Dies ist in SQL Server 2005 und höher behoben, es kann den LTM (viel weniger Overhead) verwenden, bis Sie mit 2 Quellen usw. sprechen, wenn es auf DTC erhöht wird.
  • Es gibt einen Fehler , der bedeutet, dass Sie möglicherweise Ihre Verbindungszeichenfolge optimieren müssen
 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; } } } } 

Sie können die Transaktion auch in ihre eigene gespeicherte Prozedur einfügen und so behandeln, anstatt Transaktionen in C # selbst auszuführen.

Wenn Sie es nur für db-bezogene Sachen brauchen, unterstützen einige OR-Mapper (zB NHibernate) standardmäßig Transactinos.

Es hängt auch davon ab, was Sie brauchen. Für grundlegende SQL-Transaktionen können Sie TSQL-Transaktionen versuchen, indem Sie BEGIN TRANS und COMMIT TRANS in Ihrem Code verwenden. Das ist der einfachste Weg, aber es hat Komplexität und Sie müssen vorsichtig sein, um korrekt zu committen (und Rollback).

Ich würde sowas benutzen

 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 } 

Jeder Fehler bringt Sie direkt aus der using und die Transaktion wird immer commit oder Rollback (je nachdem, was Sie sagen, es zu tun). Das größte Problem, dem wir gegenüberstanden, bestand darin, dafür zu sorgen, dass es immer eingehalten wurde. Die Verwendung stellt sicher, dass der scope der Transaktion begrenzt ist.