wake-up-neo.com

Soll ich eine Lesetransaktion festschreiben oder zurücksetzen?

Ich habe eine Leseabfrage, die ich in einer Transaktion ausführen kann, um die Isolationsstufe anzugeben. Was soll ich tun, wenn die Abfrage abgeschlossen ist?

  • Übernehmen Sie die Transaktion 
  • Machen Sie die Transaktion rückgängig
  • Nichts tun (was dazu führt, dass die Transaktion am Ende des Verwendungsblocks zurückgesetzt wird)

Welche Implikationen haben beide?

using (IDbConnection connection = ConnectionFactory.CreateConnection())
{
    using (IDbTransaction transaction = connection.BeginTransaction(IsolationLevel.ReadUncommitted))
    {
        using (IDbCommand command = connection.CreateCommand())
        {
            command.Transaction = transaction;
            command.CommandText = "SELECT * FROM SomeTable";
            using (IDataReader reader = command.ExecuteReader())
            {
                // Read the results
            }
        }

        // To commit, or not to commit?
    }
}

BEARBEITEN: Die Frage ist nicht, ob eine Transaktion verwendet werden soll oder ob es andere Möglichkeiten gibt, die Transaktionsebene festzulegen. Die Frage ist, ob es einen Unterschied macht, dass eine Transaktion, die nichts ändert, festgeschrieben oder rückgängig gemacht wird. Gibt es einen Leistungsunterschied? Hat es Auswirkungen auf andere Verbindungen? Irgendwelche anderen Unterschiede?

84
Stefan Moser

Sie verpflichten sich. Zeitraum. Es gibt keine andere vernünftige Alternative. Wenn Sie eine Transaktion gestartet haben, sollten Sie sie schließen. Durch das Commitieren werden alle Sperren freigegeben, die Sie möglicherweise bereits hatten. Dies ist bei ReadUncommitted- oder Serializable-Isolationsstufen gleichermaßen sinnvoll. Auf das implizite Rollback zu setzen - obwohl es technisch vielleicht gleichwertig ist - ist nur eine schlechte Form.

Wenn Sie das nicht überzeugt haben, stellen Sie sich einfach den nächsten Typ vor, der eine Aktualisierungsanweisung in die Mitte Ihres Codes einfügt und das implizite Rollback aufspüren muss, das auftritt und seine Daten entfernt.

47
Mark Brackett

Wenn Sie nichts geändert haben, können Sie entweder ein COMMIT oder ein ROLLBACK verwenden. Entweder werden Lesesperren, die Sie erworben haben, freigegeben. Da Sie keine weiteren Änderungen vorgenommen haben, sind sie gleichwertig.

19
Graeme Perrow

Wenn Sie mit einer Transaktion beginnen, ist es am besten, sie zu übernehmen. Wenn eine Ausnahme innerhalb Ihres Verwendungs- (Transaktions-) Blocks ausgelöst wird, wird die Transaktion automatisch zurückgesetzt.

5
Neil Barnwell

Betrachten Sie geschachtelte Transaktionen .

Die meisten RDBMSs unterstützen keine geschachtelten Transaktionen oder versuchen, sie nur sehr eingeschränkt zu emulieren.

In MS SQL Server beispielsweise wird ein Rollback in einer inneren Transaktion (die keine echte Transaktion ist, zählt nur die Transaktionsebenen!) Das Rollback des gesamten Ereignisses in der outmost - Transaktion (was der ist) echte Transaktion).

Einige Datenbank-Wrapper betrachten ein Rollback in einer inneren Transaktion als Zeichen für das Auftreten eines Fehlers und alle in der äußersten Transaktion zurücksetzen, unabhängig davon, ob die äußerste Transaktion festgeschrieben oder zurückgesetzt wurde.

Ein COMMIT ist also der sichere Weg, wenn Sie nicht ausschließen können, dass Ihre Komponente von einem Softwaremodul verwendet wird.

Bitte beachten Sie, dass dies eine allgemeine Antwort auf die Frage ist. Im Codebeispiel wird das Problem mit einer äußeren Transaktion klug umgangen, indem eine neue Datenbankverbindung geöffnet wird.

In Bezug auf die Leistung: Abhängig von der Isolationsstufe erfordern SELECTs möglicherweise einen unterschiedlichen Grad an LOCKs und temporären Daten (Momentaufnahmen). Dies wird bereinigt, wenn die Transaktion geschlossen wird. Dabei spielt es keine Rolle, ob dies über COMMIT oder ROLLBACK erfolgt. Es kann einen geringfügigen Unterschied in der CPU-Zeit geben - ein COMMIT ist wahrscheinlich schneller zu analysieren als ein ROLLBACK (zwei Zeichen weniger) und andere geringfügige Unterschiede. Dies gilt natürlich nur für schreibgeschützte Operationen!

Völlig nicht gefragt: Ein anderer Programmierer, der den Code lesen kann, könnte annehmen, dass ein ROLLBACK einen Fehlerzustand impliziert.

3
Klaws

IMHO kann es sinnvoll sein, Nur-Lese-Abfragen in Transaktionen einzubinden, da (insbesondere in Java) die Transaktion als "schreibgeschützt" bezeichnet werden kann, was wiederum der JDBC-Treiber in Betracht ziehen kann, die Abfrage zu optimieren (muss aber nicht, also niemand wird Sie trotzdem daran hindern, eine INSERT auszugeben). Z.B. Der Oracle-Treiber wird Tabellensperren für Abfragen in einer als schreibgeschützt gekennzeichneten Transaktion vollständig vermeiden, was bei stark lesegesteuerten Anwendungen viel Leistung bringt.

3
Oliver Drotbohm

Nur eine Randnotiz, aber Sie können diesen Code auch so schreiben:

using (IDbConnection connection = ConnectionFactory.CreateConnection())
using (IDbTransaction transaction = connection.BeginTransaction(IsolationLevel.ReadUncommitted))
using (IDbCommand command = connection.CreateCommand())
{
    command.Transaction = transaction;
    command.CommandText = "SELECT * FROM SomeTable";
    using (IDataReader reader = command.ExecuteReader())
    {
        // Do something useful
    }
    // To commit, or not to commit?
}

Und wenn Sie die Dinge ein wenig umstrukturieren, können Sie den using-Block für den IDataReader möglicherweise auch nach oben verschieben.

2
Joel Coehoorn

Wenn Sie die SQL in eine gespeicherte Prozedur einfügen und diese über der Abfrage hinzufügen:

set transaction isolation level read uncommitted

dann müssen Sie im C # -Code nicht durch einen Reifen springen. Das Festlegen der Transaktionsisolationsstufe in einer gespeicherten Prozedur bewirkt nicht, dass die Einstellung auf alle zukünftigen Verwendungen dieser Verbindung angewendet wird. Am Ende der gespeicherten Prozedur geht es einfach zu dem zurück, mit dem die Verbindung initialisiert wurde.

1
Eric Z Beard

ROLLBACK wird hauptsächlich im Falle eines Fehlers oder außergewöhnlicher Umstände und COMMIT im Falle eines erfolgreichen Abschlusses verwendet.

Wir sollten Transaktionen mit COMMIT (für Erfolg) und ROLLBACK (für Fehler) abschließen, selbst bei schreibgeschützten Transaktionen, bei denen dies nicht von Bedeutung ist. Tatsächlich ist es wichtig, für Konsistenz und Zukunftssicherheit.

Eine Nur-Lese-Transaktion kann in vielerlei Hinsicht logisch "fehlschlagen", beispielsweise:

  • eine Abfrage gibt nicht erwartet genau eine Zeile zurück
  • eine gespeicherte Prozedur löst eine Ausnahme aus
  • die abgerufenen Daten sind inkonsistent
  • benutzer bricht die Transaktion ab, da dies zu lange dauert
  • deadlock oder Timeout

Wenn COMMIT und ROLLBACK ordnungsgemäß für eine Nur-Lese-Transaktion verwendet werden, funktioniert es weiterhin wie erwartet, wenn zu einem bestimmten Zeitpunkt DB-Schreibcode hinzugefügt wird, z. für Caching, Prüfung oder Statistik.

Implizites ROLLBACK sollte nur in Situationen mit "schwerwiegendem Fehler" verwendet werden, wenn die Anwendung abstürzt oder mit einem nicht behebbaren Fehler, einem Netzwerkausfall, einem Stromausfall usw. beendet wird.

1
Sam Watkins

Da ein READ-Status nicht geändert wird, würde ich nichts tun. Das Durchführen eines Commits führt zu nichts, außer einen Zyklus zu verschwenden, um die Anforderung an die Datenbank zu senden. Sie haben keine Operation ausgeführt, deren Status geändert wurde. Ebenso für das Rollback.

Sie sollten jedoch sicherstellen, dass Sie Ihre Objekte bereinigen und Ihre Verbindungen zur Datenbank schließen. Wenn Sie Ihre Verbindungen nicht schließen, kann dies zu Problemen führen, wenn dieser Code wiederholt aufgerufen wird.

0
Brett McCann

Wenn Sie AutoCommit auf false setzen, dann YES.

In einem Experiment mit JDBC (Postgresql-Treiber) habe ich festgestellt, dass bei Auswahlabbrüchen (wegen Zeitüberschreitung) keine neue Auswahlabfrage initiiert werden kann, wenn nicht ein Rollback ausgeführt wird.