Transaktion innerhalb einer Transaktion in C #

7

Ich importiere eine einfache Rechnungsdatei mit C # in eine Datenbank. Ich verwende das TransactionScope, um die gesamte Operation rückgängig zu machen, wenn ein Problem auftritt.

Es ist eine knifflige Eingabedatei, in der eine Zeile nicht unbedingt einem Datensatz entspricht. Es enthält auch verknüpfte Datensätze. Eine Rechnung würde eine Kopfzeile, Werbebuchungen und dann eine Gesamtzeile enthalten. Einige der Rechnungen müssen übersprungen werden, aber ich kann nicht wissen, dass es übersprungen werden muss, bis ich die Gesamtlinie erreiche.

Eine Strategie besteht darin, die Kopfzeile, die Werbebuchungen und die gesamte Zeile im Speicher zu speichern und alles zu speichern, sobald die gesamte Zeile erreicht ist. Ich verfolge das jetzt.

Allerdings habe ich mich gefragt, ob es anders geht. Erstellen einer "geschachtelten" Transaktion um die Rechnung herum, Einfügen der Kopfzeile und der Werbebuchungen und anschließendes Aktualisieren der Rechnung, wenn die gesamte Zeile erreicht ist. Diese "geschachtelte" Transaktion wird rückgängig gemacht, wenn festgestellt wird, dass die Rechnung übersprungen werden muss, die Gesamttransaktion jedoch fortgesetzt wird.

Ist das möglich, praktisch und wie würden Sie das einrichten?

    
Rosco 08.05.2010, 16:21
quelle

5 Antworten

3

Dies wird mit einem Transaktionssicherungspunkt erreicht. Es sieht normalerweise so aus:

%Vor%

Ich habe einen Transact-SQL-basierten Pseudocode verwendet, und das ist kein Zufall. Sicherungspunkte sind ein Datenbankkonzept, und die .Net-Transaktionen unterstützen sie nicht. Sie können SqlTransaction direkt verwenden und SqlTransaction.Save verwenden oder Sie können gespeicherte T-SQL-Prozeduren verwenden, die nach einer ausnahmesicheren Vorlage erstellt wurden . Ich würde empfehlen, die .Net-Transaktionen (dh TransactionScope) in diesem Fall zu vermeiden.

    
Remus Rusanu 08.05.2010, 16:55
quelle
29

Weder die TransactionScope noch SQL Server unterstützen verschachtelte Transaktionen.

Sie können TransactionScope Instanzen verschachteln, aber dies hat nur die äußere Erscheinung einer verschachtelten Transaktion. In Wirklichkeit gibt es etwas, das als "Ambient" -Transaktion bezeichnet wird, und es kann immer nur eins sein. Welche Transaktion die Ambient-Transaktion ist, hängt davon ab, was Sie für TransactionScopeOption verwenden, wenn Sie den Bereich erstellen.

Um genauer zu erklären, überlegen Sie Folgendes:

%Vor%

Folgendes geschieht für jeden inneren Bereich:

  • inner1 wird in einer impliziten Transaktion unabhängig von outer ausgeführt. Nichts, was in DoWork1 passiert, ist garantiert atomar. Wenn dies in der Mitte fehlschlägt, haben Sie inkonsistente Daten. Jede Arbeit, die hier stattfindet, wird immer ausgeführt, unabhängig davon, was mit outer passiert.

  • inner2 wird in einer neuen Transaktion unabhängig von outer ausgeführt. Dies ist eine andere Transaktion von outer , aber es ist nicht verschachtelt. Wenn dies fehlschlägt, kann die Arbeit, die in outer ( DoOuterWork() ) und einem der anderen Bereiche ausgeführt wurde, noch festgeschrieben werden, aber hier ist der Unterschied: Wenn der Vorgang abgeschlossen ist, wird die gesamte outer Transaktion zurückgesetzt nicht macht die Arbeit innerhalb von inner2 rückgängig. Deshalb ist es nicht wirklich verschachtelt. Außerdem hat inner2 keinen Zugriff auf Zeilen, die von outer gesperrt sind. Wenn Sie also nicht vorsichtig sind, könnten Sie hier mit Deadlocks enden.

  • inner3 wird in der gleichen Transaktion als outer ausgeführt. Dies ist das Standardverhalten. Wenn DoWork3() fehlschlägt und inner3 niemals abgeschlossen wird, wird die gesamte outer - Transaktion zurückgesetzt. Wenn inner3 erfolgreich abgeschlossen wird, aber outer zurückgesetzt wird, wird auch jede Arbeit in DoWork3() zurückgesetzt.

Sie können also hoffentlich sehen, dass keine dieser Optionen tatsächlich verschachtelt ist und Ihnen nicht geben wird, was Sie wollen. Die Option Required nähert eine verschachtelte Transaktion an, bietet Ihnen jedoch nicht die Möglichkeit, bestimmte Arbeitseinheiten innerhalb der Transaktion unabhängig zu binden oder rückgängig zu machen.

Das nächste, was Sie zu echten verschachtelten Transaktionen in SQL Server bekommen können, ist die SAVE TRAN -Anweisung kombiniert mit einigen TRY/CATCH -Blöcken. Wenn Sie Ihre Logik in eine oder mehrere gespeicherte Prozeduren einfügen können, wäre dies eine gute Option.

Andernfalls müssen Sie für jede Rechnung separate Transaktionen gemäß dem Vorschlag von Oded verwenden.

    
Aaronaught 08.05.2010 16:52
quelle
2

Anstatt verschachtelte Transaktionen zu verwenden, könnten Sie eine Transaktion pro Rechnung anlegen. Auf diese Weise werden nur erfolgreiche Aktualisierungen für ganze Rechnungen durchgeführt.

Wenn Sie Transaktionen so verschachteln, wie Sie es beschreiben, besteht die Gefahr, dass die gesamte Datenmenge zurückgesetzt wird, was nicht Ihren Vorstellungen entspricht.

    
Oded 08.05.2010 16:25
quelle
2

Persönlich würde ich zuerst sehen, ob die Rechnung hinzugefügt werden muss - wenn dies der Fall ist, dann führe deine Einsätze (in einer Transaktion) aus. Ansonsten wechseln Sie einfach zur nächsten Rechnung.

Ich denke nicht, dass es so toll ist, es einzufügen und dann einen Rollback auf die Art und Weise auszuführen, wie Sie es beschreiben.

    
David_001 08.05.2010 16:40
quelle
0

Eine fehlgeschlagene innere Transaktion würde die äußere Transaktion rückgängig machen, sodass Sie diese Route nicht verwenden können.

Sie können es jedoch fälschen, indem Sie eine temp (oder eine load) -Tabelle verwenden. Fügen Sie jede Rechnung transaktional in die Auslastungstabelle ein und verschieben Sie sie dann automatisch von der Auslastungstabelle in eine permanente Tabelle.

    
Mark Brackett 08.05.2010 16:49
quelle

Tags und Links