Warum benötige ich eine Transaktion im Ruhezustand für schreibgeschützte Vorgänge?

106

Warum benötige ich eine Transaktion im Ruhezustand für schreibgeschützte Vorgänge?

Sperrt die folgende Transaktion die Datenbank?

Beispielcode zum Abrufen aus der Datenbank:

Transaction tx = HibernateUtil.getCurrentSession().beginTransaction(); // why begin transaction?
//readonly operation here

tx.commit() // why tx.commit? I don't want to write anything

Kann ich session.close() anstelle von verwenden tx.commit()?

user93796
quelle
9
Die Transaktion wird von der DB selbst benötigt. Sie können über den Autocommit-Modus hier lesen: community.jboss.org/wiki/…
Bhesh Gurung
@ BheshGurung Ich denke, wir benötigen Transkation nur für den Schreibvorgang
user93796
4
Haben Sie den Teil "Auto-Commit-Mythen entlarven" im Link gelesen?
Bhesh Gurung

Antworten:

131

Möglicherweise haben Sie tatsächlich Gründe, Transaktionen als schreibgeschützt zu markieren.

  1. Transaktionen zum Lesen sehen in der Tat seltsam aus und in diesem Fall werden häufig keine Methoden für Transaktionen markiert. JDBC erstellt jedoch trotzdem eine Transaktion. Es funktioniert nur, autocommit=truewenn keine andere Option explizit festgelegt wurde.
  2. Es gibt jedoch keine Garantie dafür, dass Ihre Methode nicht in die Datenbank schreibt. Wenn Sie die Methode als markieren @Transactional(readonly=true), setzt Spring die JDBC-Transaktion in einen schreibgeschützten Modus. Auf diese Weise bestimmen Sie, ob im Rahmen dieser Transaktion tatsächlich in die Datenbank geschrieben werden kann. Wenn Ihre Architektur umständlich ist und einige Teammitglieder möglicherweise eine Änderungsabfrage dort platzieren, wo dies nicht erwartet wird, weist dieses Flag Sie auf den problematischen Ort hin.
  3. Auch schreibgeschützte Transaktionen können von DBs optimiert werden, dies ist jedoch natürlich DB-spezifisch. Beispielsweise hat MySQL dies nur in InnoDB ab Version 5.6.4 unterstützt.
  4. Wenn Sie JDBC nicht direkt verwenden, sondern ein ORM, kann dies problematisch sein. Zum Beispiel sagt die Hibernate-Community, dass das Arbeiten außerhalb der Transaktion zu unvorhersehbarem Verhalten führen kann. Dies liegt daran, dass der Ruhezustand die Transaktion öffnet, sie jedoch nicht selbst schließt. Daher wird die Verbindung zum Verbindungspool zurückgegeben, wobei die Transaktion nicht festgeschrieben wird. Was passiert dann? JDBC schweigt, daher ist dies implementierungsspezifisch (MySQL setzt die Transaktion zurück, Oracle afair schreibt sie fest). Dies kann auch auf der Ebene des Verbindungspools konfiguriert werden (z. B. bietet C3P0 eine solche Option, standardmäßig ein Rollback).
  5. Wenn es um den Ruhezustand geht, setzt Spring den FlushMode bei schreibgeschützten Transaktionen auf MANUAL, was zu anderen Optimierungen führt, beispielsweise, dass keine schmutzigen Prüfungen erforderlich sind.
  6. Möglicherweise möchten Sie die Transaktionsisolationsstufe überschreiben oder explizit festlegen. Dies wirkt sich auch auf Lesetransaktionen aus, da Sie nicht festgeschriebene Änderungen lesen oder nicht lesen, Phantom-Lesevorgängen ausgesetzt sein möchten usw.

Zusammenfassend lässt sich sagen, dass Sie beide Wege gehen können, aber die Konsequenzen verstehen müssen.

Stanislav Bashkyrtsev
quelle
Vielen Dank für die Antwort. Ich verwende den Ruhezustand (nativer Ruhezustand, nicht jpa). Der Ruhezustand zwingt mich jedoch, eine Transkation zu starten, bevor ich eine Datenbankoperation ausführe , wenn ja wie?
user93796
Das schreibgeschützte Flag ist tatsächlich für die Verbindung gesetzt, nicht für die Transaktion selbst, und Sie können nicht einfach so über den Ruhezustand darauf zugreifen. Sie müssen die Spring Transaction-Unterstützung verwenden und entweder Anmerkungen oder eine XML-basierte Transaktionskonfiguration verwenden. Auf diese Weise übernimmt Spring das Eigentum an der Verbindungs- und Transaktionsverwaltung anstelle von Hibernate.
Stanislav Bashkyrtsev
1
Sehr gut erklärt! Ein anderer Artikel von Mark Richards erklärt ziemlich gut die Fallstricke des schreibgeschützten Flags in der Transaktionsanmerkung - ibm.com/developerworks/java/library/j-ts1/index.html .
Mahesh
47

Alle Datenbankanweisungen werden im Kontext einer physischen Transaktion ausgeführt, auch wenn wir keine expliziten Transaktionsgrenzen deklarieren (BEGIN / COMMIT / ROLLBACK).

Wenn Sie Transaktionsgrenzen nicht explizit deklarieren, muss jede Anweisung in einer separaten Transaktion ( autocommitModus) ausgeführt werden. Dies kann sogar zum Öffnen und Schließen einer Verbindung pro Anweisung führen, es sei denn, Ihre Umgebung kann die Verbindung pro Thread binden.

Wenn Sie einen Dienst als @Transactionaldeklarieren, erhalten Sie eine Verbindung für die gesamte Transaktionsdauer, und alle Anweisungen verwenden diese einzelne Isolationsverbindung. Dies ist viel besser, als überhaupt keine expliziten Transaktionen zu verwenden.

Bei großen Anwendungen haben Sie möglicherweise viele gleichzeitige Anforderungen, und eine Reduzierung der Anforderungsrate für die Erfassung von Datenbankverbindungen verbessert definitiv die Gesamtleistung Ihrer Anwendung.

JPA erzwingt keine Transaktionen für Lesevorgänge. Nur Schreibvorgänge lösen eine für Transaktionen erforderliche Ausnahme aus, falls Sie vergessen, einen Transaktionskontext zu starten. Trotzdem ist es immer besser, Transaktionsgrenzen auch für schreibgeschützte Transaktionen zu deklarieren (im Frühjahr @Transactionalkönnen Sie schreibgeschützte Transaktionen markieren, was einen großen Leistungsvorteil bietet).

Vlad Mihalcea
quelle
1
"... dann muss jede Anweisung in einer separaten Transaktion ausgeführt werden". Der Container führt die Stapelverarbeitung nicht automatisch durch?
Arash
Die Stapelverarbeitung dient zum Ändern und nicht zum Lesen von Daten. Und auch so, JDBC Dosierung ist nicht standardmäßig aktiviert , wenn JPA und Hibernate.
Vlad Mihalcea
1
Danke Vlad. Ich habe einige Ihrer Artikel gelesen. Sie sind wirklich nützlich.
Arash
Dieser stackoverflow.com/q/34797480/179850 scheint Ihrer Behauptung , dass schreibgeschützte Transaktionen einen großen Leistungsvorteil haben, ein wenig zu widersprechen. Zumindest scheint dies im Zusammenhang mit dem Winterschlaf nicht der Fall zu sein.
Nimai
Nein, das tut es nicht. Hier geht es darum, schreibgeschützt einzustellen, während es bei mir darum geht, das automatische Festschreiben zu vermeiden.
Vlad Mihalcea
17

Transaktionen setzen tatsächlich Sperren für die Datenbank - gute Datenbank-Engines behandeln gleichzeitige Sperren auf sinnvolle Weise - und sind bei schreibgeschützter Verwendung nützlich, um sicherzustellen, dass keine andere Transaktion Daten hinzufügt, die Ihre Ansicht inkonsistent machen. Sie möchten immer eine Transaktion (obwohl es manchmal sinnvoll ist, die Isolationsstufe zu optimieren, ist es am besten, dies zunächst nicht zu tun). Wenn Sie während Ihrer Transaktion nie in die Datenbank schreiben, ist das Festschreiben und Zurücksetzen der Transaktion gleich (und sehr billig).

Wenn Sie Glück haben und Ihre Abfragen an die Datenbank so sind, dass der ORM sie immer einzelnen SQL-Abfragen zuordnet , können Sie ohne explizite Transaktionen davonkommen und sich auf das integrierte Autocommit-Verhalten der DB verlassen. ORMs sind jedoch relativ komplexe Systeme Daher ist es überhaupt nicht sicher, sich auf ein solches Verhalten zu verlassen, wenn Sie nicht viel mehr arbeiten, um zu überprüfen, was die Implementierung tatsächlich tut. Das Einschreiben der expliziten Transaktionsgrenzen ist weitaus einfacher (insbesondere, wenn Sie dies mit AOP oder einer ähnlichen ORM-gesteuerten Technik tun können; ab Java 7 könnte vermutlich auch Try-with-Resources verwendet werden).

Donal Fellows
quelle
14

Es spielt keine Rolle, ob Sie nur lesen oder nicht - die Datenbank muss weiterhin Ihre Ergebnismenge verfolgen, da andere Datenbankclients möglicherweise Daten schreiben möchten, die Ihre Ergebnismenge ändern würden.

Ich habe fehlerhafte Programme gesehen, die riesige Datenbanksysteme töten, weil sie nur Daten lesen, aber niemals festschreiben, wodurch das Transaktionsprotokoll wächst, weil die Datenbank die Transaktionsdaten nicht vor einem COMMIT oder ROLLBACK freigeben kann, selbst wenn der Client nichts getan hat stundenlang.

Ingo
quelle