TransactionScope vs Transaktion in LINQ to SQL

76

Was sind die Unterschiede zwischen dem klassischen Transaktionsmuster in LINQ und SQL?

using(var context = Domain.Instance.GetContext())
{
    try
    {
        context.Connection.Open();
        context.Transaction = context.Connection.BeginTransaction();
        /*code*/
        context.Transaction.Commit();
    }
    catch
    {
        context.Transaction.Rollback();
    }         
}

gegen das TransactionScope-Objekt

using (var context = Domain.Instance.GetContext())
using (var scope = new TransactionScope())
{
    try
    {
        /*code*/
        scope.Complete();
    }
    catch
    {
    }
}
Ben McNiel
quelle

Antworten:

37

Linq2SQL verwendet eine implizite Transaktion. Wenn alle Ihre Aktualisierungen innerhalb einer einzigen Übermittlung durchgeführt werden, müssen Sie die Transaktion möglicherweise nicht selbst abwickeln.

Aus der Dokumentation (Schwerpunkt Mine):

Wenn Sie SubmitChanges aufrufen, prüft LINQ to SQL, ob sich der Aufruf im Bereich einer Transaktion befindet oder ob die Transaktionseigenschaft (IDbTransaction) auf eine vom Benutzer gestartete lokale Transaktion festgelegt ist. Wenn keine Transaktion gefunden wird, startet LINQ to SQL eine lokale Transaktion (IDbTransaction) und verwendet sie zum Ausführen der generierten SQL-Befehle. Wenn alle SQL-Befehle erfolgreich ausgeführt wurden, schreibt LINQ to SQL die lokale Transaktion fest und gibt sie zurück.

TGnat
quelle
10
Wenn Sie etwas mit zyklischen Eigenschaften (häufig) senden müssen, stoßen Sie in LINQ to SQL auf einen Fehler, bei dem Sie einen Teil jeder 2-Wege-Referenz entfernen, senden, die 2-Wege-Referenzen reparieren und erneut senden müssen. Sie müssen dies alles in Ihre eigene Transaktion einbinden, um dies zu tun. Es ist ein allgemeines Bedürfnis, daher ist "Mach dir keine Sorgen" nicht die beste Antwort.
Chris Moschini
76

Es sollte beachtet werden, dass bei Verwendung TransactionScopevon das try/catchKonstrukt, das Sie haben, nicht benötigt wird . Sie müssen lediglich den Bereich aufrufen Complete, um die Transaktion beim Beenden des Bereichs festzuschreiben.

Dies TransactionScopeist normalerweise die bessere Wahl, da Sie damit Aufrufe an andere Methoden verschachteln können, für die möglicherweise eine Transaktion erforderlich ist, ohne den Transaktionsstatus weitergeben zu müssen.

Wenn Sie BeginTransactiondas DbConnectionObjekt aufrufen , müssen Sie dieses Transaktionsobjekt weitergeben, wenn Sie andere Vorgänge in derselben Transaktion, jedoch mit einer anderen Methode ausführen möchten.

Mit TransactionScopesolange der Umfang existiert, wird sie alles im Griff, dass die Register mit dem aktuellen Transactionauf dem Thread, den Code sauberer zu machen und besser wartbar.

Darüber hinaus haben Sie den zusätzlichen Vorteil, dass Sie andere Ressourcen verwenden können, die an Transaktionen teilnehmen können, nicht nur die Verbindung zur Datenbank.

Es sollte beachtet werden, dass Sie in Situationen, in denen Sie Ihre Verbindungen und Datenbankoperationen optimal nutzen müssen, diese möglicherweise nicht verwenden möchten TransactionScope. Selbst für eine einzelne Datenbank besteht die Möglichkeit, dass der Distributed Transaction Coordinator verwendet wird und die Transaktion in eine verteilte Transaktion umgewandelt wird (auch für eine einzelne Datenbankverbindung).

In diesen Fällen möchten Sie möglicherweise eine verbindungsspezifische Transaktion weitergeben, während Sie Ihr Design durcheinander bringen.

Oder , wenn Sie wissen , dass Sie eine Ressource konsequent nutzen werden (und auf dem gleichen Thread), möchten Sie vielleicht eine Klasse erstellen , die Referenz zählt Ihre Verbindung / Transaktion.

Sie würden eine Klasse erstellen, die beim Erstellen Ihre Ressource erstellt / die Anzahl erhöht. Es würde auch implementieren IDisposable(in dem Sie dekrementieren / freigeben / festschreiben / abbrechen würden, wenn die Anzahl Null ist) und die Anzahl in einer Variablen speichern, die ThreadStaticAttributeauf sie angewendet wurde.

Auf diese Weise können Sie die Transaktionsverwaltung vom Logikcode trennen und dennoch eine einzelne Ressource ziemlich effizient verwalten (anstatt zu einer verteilten Transaktion zu eskalieren).

casperOne
quelle
Wenn ich eine einzelne Verbindung mit einer Transaktion verwende, ist es dann nicht dasselbe? Ich meine, Sie vermeiden verteilte Transaktionen ..
GorillaApe
@Parhs Hängt davon ab, ob Sie andere Transaktionsressourcen in der Transaktion mit der einzelnen Datenbankverbindung registriert haben oder nicht.
CasperOne
Mein Provider erlaubt keine verschachtelten Transaktionen (Datenbank). Gibt es also immer noch ein Problem?
GorillaApe
2
@Parhs Es geht nicht um den Datenbankanbieter, aber Sie könnten ein Transaktionsdateisystem, einen Transaktionswebdienst usw. haben. Wenn diese Dinge in einer Transaktion mit einer einzelnen Datenbankverbindung enthalten sind, tritt der DTC ein.
casperOne
21

Ein großer Unterschied (Lektion auf die harte Tour gelernt): TransactionScope verwendet MS DTC für das Transaktionsmanagement.

Wenn Ihre Anwendung nur Datenbanktransaktionen verwalten muss und keine Dienste oder Remoteaufrufe beteiligt sind, können Sie die potenziellen Probleme im Zusammenhang mit MS DTC überspringen, indem Sie die für Datenbanken native Transaktion (DbTransactions) verwenden.

Mayank
quelle
Ich habe das auch gerade auf die harte Tour gelernt! Aber froh, einen Albtraum mit msdtc gelöst zu haben
DevDave
Mayank (oder sonst jemand). Ich hatte weitere Probleme mit Transaction und UnitTesting. Können Sie mir bei diesem stackoverflow.com/questions/9636533/… überhaupt helfen ?
DevDave
6
Dies ist nicht immer der Fall. TransactionScopeEskaliert je nach Bedarf von einer Kernel-Transaktion zu einer DTC-Transaktion. Dies ist jedoch alles vor Ihnen verborgen. Der wichtige Punkt ist, dass dies nicht immer , sondern nach Bedarf geschieht .
CasperOne
Nicht, wenn Sie denselben Datenkontext verwenden.
Dasith Wijes
7

TransactionScope bietet eine einheitliche Verwaltung für alle Ressourcenmanager (SQL Server, Active Directory, Dateisystem usw.). Darüber hinaus kann man einen eigenen Ressourcenmanager schreiben: Code, der den Transaktionsbereich erkennt, sich diesem anschließt und genau wie SQL Server funktioniert: Änderungen wie andere Teilnehmer der Transaktion festschreiben oder zurücksetzen. Ich war der Meinung, dass TransactionScope Mainstream ist, und vergaß native MS SQL-Transaktionen, bis sie in eine große Falle gerieten: Die Windows Server 2008 WEB Edition verfügt über einen eingeschränkten Distributed Transaction Coordinator-Dienst, und der Transaktionsbereich funktioniert nur auf einem einzelnen Computer. Ihre ASP.NET-Anwendung schlägt auf diesem System fehl, wenn IIS und SQL Server auf verschiedenen Computern installiert sind. Berücksichtigen Sie, dass sich die meisten Public Domain-Anbieter, die Windows Server WEB Edition und SQL Server anbieten, auf separaten Servern befinden. Dies bedeutet, dass Sie mit nativen Transaktionen mithilfe der expliziten Transaktionsverwaltung arbeiten müssen.

Gediminas Bukauskas
quelle
4

Ich glaube, sie sind im Grunde die gleichen, die die TransactionScope-Klasse mit der zugrunde liegenden ADO.NET-Verbindung verbindet, um die Transaktion zu erstellen und entweder festzuschreiben oder zurückzusetzen. Die TransactionScope-Klasse wurde gerade erstellt, um die Arbeit mit ADO.NET-Persistenz sauberer zu gestalten.

Bearbeiten: Klarstellung meiner Aussage in Bezug auf die Hinzufügung von casperOne Es ist das TransactionScope, das die Transaktion erstellt, und die Verbindung sieht dann die Transaktion, die vom TransactionScope erstellt wurde, und verwendet sie, da sie verfügbar ist.

Chris Marisic
quelle
@Christ Marisic: Es ist umgekehrt. Die Verbindung sucht nach dem Vorhandensein einer Transaktion für den aktuellen Thread, die von TransactionScope erstellt wird. Wenn es eine gibt, wird sie bei der Transaktion registriert. Der Koordinator teilt der Verbindung dann mit, dass sie festgeschrieben oder zurückgesetzt werden soll.
casperOne