Richtige Verwendung von flush () in JPA / Hibernate

109

Ich habe Informationen über die flush () -Methode gesammelt, bin mir aber nicht ganz sicher, wann und wie ich sie richtig verwenden soll. Nach dem, was ich gelesen habe, ist mein Verständnis, dass der Inhalt des Persistenzkontexts mit der Datenbank synchronisiert wird, dh ausstehende Anweisungen ausgeben oder Entitätsdaten aktualisieren.

Jetzt habe ich folgendes Szenario mit zwei Entitäten Aund B(in einer Eins-zu-Eins-Beziehung, aber nicht von JPA erzwungen oder modelliert). Ahat eine zusammengesetzte PK, die manuell eingestellt wird, und hat auch ein automatisch generiertes IDENTITY-Feld recordId. Dies recordIdsollte Bals Fremdschlüssel an die Entität geschrieben werden A. Ich spare Aund Bin einer einzigen Transaktion. Das Problem ist, dass der automatisch generierte Wert A.recordIdinnerhalb der Transaktion nicht verfügbar ist, es sei denn, ich rufe em.flush()nach dem Aufruf explizit em.persist()an A. (Wenn ich eine automatisch generierte IDENTITY PK habe, wird der Wert direkt in der Entität aktualisiert, aber das ist hier nicht der Fall.)

Kann em.flush()bei Verwendung innerhalb einer Transaktion Schaden anrichten?

MicSim
quelle

Antworten:

147

Wahrscheinlich sind die genauen Details von der em.flush()Implementierung abhängig. Im Allgemeinen können JPA-Anbieter wie Hibernate die SQL-Anweisungen, die sie an die Datenbank senden sollen, zwischenspeichern, häufig bis Sie die Transaktion tatsächlich festschreiben. Wenn Sie beispielsweise aufrufen em.persist(), merkt sich Hibernate, dass eine Datenbank INSERT erstellt werden muss, führt die Anweisung jedoch erst aus, wenn Sie die Transaktion festschreiben. Afaik, dies geschieht hauptsächlich aus Leistungsgründen.

In einigen Fällen möchten Sie trotzdem, dass die SQL-Anweisungen sofort ausgeführt werden. Im Allgemeinen, wenn Sie das Ergebnis einiger Nebenwirkungen wie eines automatisch generierten Schlüssels oder eines Datenbank-Triggers benötigen.

Was em.flush()tut , ist die interne SQL Anweisungen Cache zu leeren, und führen Sie es sofort in die Datenbank.

Fazit: Es wird kein Schaden angerichtet, nur Sie könnten einen (geringfügigen) Leistungseinbruch erleiden, da Sie die Entscheidungen des JPA-Anbieters hinsichtlich des besten Zeitpunkts für das Senden von SQL-Anweisungen an die Datenbank überschreiben.

Flavio
quelle
1
Was er sagte. Das Verhalten von em.flush () spiegelt java.io.Flushable.flush () wider, bei dem alle gepufferten Daten an ein geeignetes Ziel gesendet werden.
Erik
4
Wenn flush () Daten an die Datenbank sendet? Was passiert, wenn danach eine Ausnahme ausgelöst wird? Wird der Entity Manager alles zurücksetzen? sogar die Daten in der ersten Spülung geschrieben?
Jaime Hablutzel
100
flush () sendet SQL-Anweisungen wie INSERT, UPDATE usw. an die Datenbank. Es wird kein COMMIT gesendet. Wenn Sie also nach einem flush () eine Ausnahme haben, können Sie trotzdem einen vollständigen Rollback durchführen.
Flavio
17
Sie können die Datenbank zurücksetzen, es werden jedoch keine Änderungen an den Objekten zurückgesetzt, z. B. automatisch inkrementierte 'Version', automatisch generierte ID usw. Außerdem wird der Entitätsmanager nach einem Rollback geschlossen. Beachten Sie jedoch, dass insbesondere die automatisch inkrementierte 'Version' eine OptimisticLockException verursachen kann, wenn Sie versuchen, das Objekt mit einer anderen Sitzung zusammenzuführen.
Peter Davis
10
Neben dem Auslösen von Nebenwirkungen besteht ein weiterer Grund für die Verwendung von flush () darin, dass Sie die Auswirkungen eines Vorgangs in der Datenbank mit JPQL / HQL lesen möchten (z. B. in einem Test). JPA kann bei der Ausführung dieser Abfragen keine zwischengespeicherten Daten verwenden, sodass nur Inhalte gelesen werden, die sich tatsächlich in der Datenbank befinden.
Sleske
2

Machen em.flush()Sie mehr als nur das Senden der zwischengespeicherten SQL-Befehle. Es wird versucht, den Persistenzkontext mit der zugrunde liegenden Datenbank zu synchronisieren. Es kann viel Zeit in Ihren Prozessen verursachen, wenn Ihr Cache zu synchronisierende Sammlungen enthält.

Vorsicht bei der Verwendung.

Ricardo Nakashima
quelle
1

Kann em.flush () Schaden anrichten, wenn es innerhalb einer Transaktion verwendet wird?

Ja, es kann Sperren in der Datenbank länger als nötig halten.

Im Allgemeinen delegieren Sie bei Verwendung von JPA die Transaktionsverwaltung an den Container (auch bekannt als CMT - mithilfe der @ Transactional-Annotation für Geschäftsmethoden). Dies bedeutet, dass eine Transaktion beim Eingeben der Methode automatisch gestartet und am Ende festgeschrieben / zurückgesetzt wird. Wenn Sie den EntityManager die Datenbanksynchronisierung durchführen lassen, wird die Ausführung von SQL-Anweisungen erst unmittelbar vor dem Festschreiben ausgelöst, was zu kurzlebigen Sperren in der Datenbank führt. Andernfalls behalten Ihre manuell geleerten Schreibvorgänge möglicherweise Sperren zwischen dem manuellen Löschen und dem automatischen Festschreiben bei, die je nach verbleibender Ausführungszeit der Methode lang sein können.

Stellt fest, dass eine Operation automatisch einen Flush auslöst: Ausführen einer nativen Abfrage für dieselbe Sitzung (EM-Status muss geleert werden, damit die SQL-Abfrage erreichbar ist), Einfügen von Entitäten mit der nativ generierten ID (von der Datenbank generiert, daher muss die Einfügeanweisung lauten ausgelöst, damit der EM die generierte ID abrufen und Beziehungen ordnungsgemäß verwalten kann)

Gab
quelle