Ich habe eine Leseabfrage, die ich innerhalb einer Transaktion ausführe, damit ich die Isolationsstufe angeben kann. Was soll ich tun, wenn die Abfrage abgeschlossen ist?
- Übernehmen Sie die Transaktion
- Setzen Sie die Transaktion zurück
- Tun Sie nichts (was dazu führt, dass die Transaktion am Ende des using-Blocks zurückgesetzt wird)
Was bedeutet es, dies zu tun?
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, ob eine Transaktion, die nichts ändert, festgeschrieben oder zurückgesetzt wird. Gibt es einen Leistungsunterschied? Betrifft es andere Verbindungen? Irgendwelche anderen Unterschiede?
sql
database
transactions
Stefan Moser
quelle
quelle
Antworten:
Sie verpflichten sich. Zeitraum. Es gibt keine andere sinnvolle Alternative. Wenn Sie eine Transaktion gestartet haben, sollten Sie sie schließen. Das Festschreiben gibt alle Sperren frei, die Sie möglicherweise hatten, und ist bei ReadUncommitted- oder Serializable-Isolationsstufen gleichermaßen sinnvoll. Sich auf implizites Rollback zu verlassen - obwohl es vielleicht technisch gleichwertig ist - ist nur eine schlechte Form.
Wenn Sie das nicht überzeugt hat, stellen Sie sich den nächsten vor, der eine Update-Anweisung in die Mitte Ihres Codes einfügt und den impliziten Rollback aufspüren und seine Daten entfernen muss.
quelle
Wenn Sie nichts geändert haben, können Sie entweder ein COMMIT oder ein ROLLBACK verwenden. In beiden Fällen werden alle von Ihnen erworbenen Lesesperren freigegeben, und da Sie keine weiteren Änderungen vorgenommen haben, sind diese gleichwertig.
quelle
Wenn Sie eine Transaktion beginnen, empfiehlt es sich immer, sie festzuschreiben. Wenn eine Ausnahme in Ihrem Verwendungsblock (Transaktionsblock) ausgelöst wird, wird die Transaktion automatisch zurückgesetzt.
quelle
IMHO kann es sinnvoll sein, schreibgeschützte Abfragen in Transaktionen einzuschließen, da Sie (insbesondere in Java) festlegen können, dass die Transaktion "schreibgeschützt" ist, was wiederum der JDBC-Treiber in Betracht ziehen kann, die Abfrage zu optimieren (muss dies aber nicht, also niemand wird Sie
INSERT
trotzdem daran hindern, eine auszustellen ). Beispielsweise vermeidet der Oracle-Treiber Tabellensperren bei Abfragen in einer als schreibgeschützt gekennzeichneten Transaktion vollständig, wodurch bei stark lesegesteuerten Anwendungen eine hohe Leistung erzielt wird.quelle
Betrachten Sie verschachtelte Transaktionen .
Die meisten RDBMS unterstützen keine verschachtelten Transaktionen oder versuchen, diese auf sehr begrenzte Weise zu emulieren.
In MS SQL Server wird beispielsweise durch ein Rollback in einer inneren Transaktion (bei der es sich nicht um eine echte Transaktion handelt, MS SQL Server zählt nur die Transaktionsebenen!) Alles zurückgesetzt, was in der äußersten Transaktion (der realen Transaktion) geschehen ist.
Einige Datenbank-Wrapper betrachten ein Rollback in einer inneren Transaktion möglicherweise als Zeichen dafür, dass ein Fehler aufgetreten ist, und setzen alles in der äußersten Transaktion zurück, 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. Das Codebeispiel umgeht das Problem mit einer äußeren Transaktion geschickt, 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 (Snapshots). Dies wird bereinigt, wenn die Transaktion geschlossen wird. Es spielt keine Rolle, ob dies über COMMIT oder ROLLBACK erfolgt. Möglicherweise gibt es einen unbedeutenden Unterschied in der CPU-Zeit - ein COMMIT lässt sich wahrscheinlich schneller 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 eine Fehlerbedingung impliziert.
quelle
Nur eine Randnotiz, aber Sie können diesen Code auch so schreiben:
Und wenn Sie die Dinge nur ein wenig neu strukturieren, können Sie möglicherweise auch den using-Block für den IDataReader nach oben verschieben.
quelle
Wenn Sie die SQL in eine gespeicherte Prozedur einfügen und diese über der Abfrage hinzufügen:
dann müssen Sie nicht durch irgendwelche Reifen im C # -Code springen. Das Festlegen der Transaktionsisolationsstufe in einer gespeicherten Prozedur führt nicht dazu, dass die Einstellung für alle zukünftigen Verwendungen dieser Verbindung gilt (worüber Sie sich bei anderen Einstellungen Sorgen machen müssen, da die Verbindungen zusammengefasst werden). Am Ende der gespeicherten Prozedur wird nur auf das zurückgegriffen, mit dem die Verbindung initialisiert wurde.
quelle
ROLLBACK wird meistens bei Fehlern oder außergewöhnlichen Umständen und COMMIT bei erfolgreichem Abschluss verwendet.
Wir sollten Transaktionen mit COMMIT (für den Erfolg) und ROLLBACK (für den Misserfolg) abschließen, selbst bei schreibgeschützten Transaktionen, bei denen dies keine Rolle zu spielen scheint. Tatsächlich ist es wichtig für Konsistenz und Zukunftssicherheit.
Eine schreibgeschützte Transaktion kann auf viele Arten logisch "fehlschlagen", zum Beispiel:
Wenn COMMIT und ROLLBACK für eine schreibgeschützte Transaktion ordnungsgemäß verwendet werden, funktioniert es weiterhin wie erwartet, wenn irgendwann DB-Schreibcode hinzugefügt wird, z. B. für Caching, Überwachung oder Statistik.
Implizites ROLLBACK sollte nur in Situationen mit "schwerwiegenden Fehlern" verwendet werden, in denen die Anwendung mit einem nicht behebbaren Fehler, einem Netzwerkfehler, einem Stromausfall usw. abstürzt oder beendet wird.
quelle
Da ein READ den Status nicht ändert, würde ich nichts tun. Das Ausführen eines Commits führt nur dazu, dass ein Zyklus zum Senden der Anforderung an die Datenbank verschwendet wird. Sie haben keine Operation ausgeführt, deren Status geändert wurde. Ebenso für den 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.
quelle
Wenn Sie AutoCommit auf false setzen, dann JA.
In einem Experiment mit JDBC (Postgresql-Treiber) stellte ich fest, dass Sie bei Unterbrechungen der Auswahlabfrage (aufgrund eines Zeitlimits) keine neue Auswahlabfrage initiieren können, es sei denn, Sie führen ein Rollback durch.
quelle
In Ihrem Codebeispiel, wo Sie haben
// Mach etwas Nützliches
Führen Sie eine SQL-Anweisung aus, die Daten ändert?
Wenn nicht, gibt es keine "Lese" -Transaktion ... Nur Änderungen von Anweisungen zum Einfügen, Aktualisieren und Löschen (Anweisungen, die Daten ändern können) befinden sich in einer Transaktion ... Es handelt sich um die Sperren von SQL Der Server legt die Daten, die Sie lesen, aufgrund ANDERER Transaktionen an, die diese Daten betreffen. Die Stufe dieser Sperren hängt von der SQL Server-Isolationsstufe ab.
Sie können jedoch nichts festschreiben oder zurückgeben, wenn Ihre SQL-Anweisung nichts geändert hat.
Wenn Sie Daten ändern, können Sie die Isolationsstufe ändern, ohne explizit eine Transaktion zu starten ... Jede einzelne SQL-Anweisung ist implizit in einer Transaktion enthalten. Das explizite Starten einer Transaktion ist nur erforderlich, um sicherzustellen, dass sich zwei oder mehr Anweisungen innerhalb derselben Transaktion befinden.
Wenn Sie nur die Transaktionsisolationsstufe festlegen möchten, setzen Sie den CommandText eines Befehls einfach auf "Set Transaction Isolation Level Repeatable Read" (oder eine beliebige gewünschte Stufe), setzen Sie den CommandType auf CommandType.Text und führen Sie den Befehl aus. (Sie können Command.ExecuteNonQuery () verwenden.)
HINWEIS: Wenn Sie MULTIPLE-Leseanweisungen ausführen und möchten, dass alle den gleichen Status der Datenbank wie die erste "sehen", müssen Sie die Isolationsstufe auf "Wiederholbares Lesen" oder "Serialisierbar" setzen.
quelle
Müssen Sie andere daran hindern, dieselben Daten zu lesen? Warum eine Transaktion verwenden?
@Joel - Meine Frage wäre besser formuliert als "Warum eine Transaktion für eine Leseabfrage verwenden?"
@Stefan - Wenn Sie AdHoc SQL und keinen gespeicherten Prozess verwenden möchten, fügen Sie einfach das WITH (NOLOCK) nach den Tabellen in der Abfrage hinzu. Auf diese Weise entsteht kein Aufwand (wenn auch nur minimal) in der Anwendung und der Datenbank für eine Transaktion.
EDIT @ Kommentar 3: Da Sie "sqlserver" in den Frage-Tags hatten, hatte ich angenommen, dass MSSQLServer das Zielprodukt war. Nachdem dieser Punkt geklärt wurde, habe ich die Tags bearbeitet, um die spezifische Produktreferenz zu entfernen.
Ich bin mir immer noch nicht sicher, warum Sie überhaupt eine Transaktion für eine Leseoperation durchführen möchten.
quelle