Ruhezustand: flush () und commit ()

77

Ist es empfehlenswert, org.hibernate.Session.flush()separat anzurufen ?

Wie in den org.hibernate.SessionDokumenten gesagt ,

Muss am Ende einer Arbeitseinheit aufgerufen werden, bevor die Transaktion festgeschrieben und die Sitzung geschlossen wird (je nach Flush-Modus ruft Transaction.commit () diese Methode auf).

Könnten Sie den Zweck eines flush()expliziten Anrufs erläutern, wenn org.hibernate.Transaction.commit()dies bereits geschehen wird?

bsiamionau
quelle
Sie könnten das sessionFactorymit der @TransactionalAnnotation injizieren , wenn Sie es sich ansehen. Ab diesem Zeitpunkt muss Ihr Code nicht mehr überall transaktional sein (dies ist jedoch in einigen Situationen erforderlich).
Löwe
Ich bin gerade auf eine interessante Situation in meinem Code gestoßen. Ich musste eine Entität zusammenführen, für die bereits eine ID aus der Client-App generiert wurde, und dann dieselbe Entität aktualisieren, um datenbankgenerierte Felder wie das Erstellungsdatum und die Änderung zu erhalten. Ohne den Aufruf von session.flush () würde eine Ausnahme für nicht gefundene Objekte ausgelöst, da der Zusammenführungsaufruf manchmal bis zum Ende der Transaktion ignoriert wird. Wenn ich Flush unmittelbar nach dem Zusammenführungsaufruf hinzufüge, wird der Ruhezustand gezwungen, die eigentliche Abfrage durchzuführen und später zu aktualisieren Das Objekt funktioniert, weil es jetzt in der Datenbank existiert!
Japheth Ongeri - Inkalimeva

Antworten:

96

Im Handbuch für den Ruhezustand sehen Sie dieses Beispiel

Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();

for (int i = 0; i < 100000; i++) {
    Customer customer = new Customer(...);
    session.save(customer);
    if (i % 20 == 0) { // 20, same as the JDBC batch size
        // flush a batch of inserts and release memory:
        session.flush();
        session.clear();
    }
}

tx.commit();
session.close();

Ohne den Aufruf der Flush-Methode würde Ihr Cache der ersten Ebene eine OutOfMemoryException auslösen

Sie können sich auch diesen Beitrag über das Spülen ansehen

Aleksei Bulgak
quelle
Könnten Sie auf diesen Artikel verweisen?
bsiamionau
5
Diese Antwort gibt einen speziellen Fall an, in dem es eine gute Idee ist, Flush explizit aufzurufen, aber ich denke nicht, dass sie die allgemeine Frage anspricht, ob man dies immer tun sollte.
Dave L.
Hallo @KorayTugay. Ich habe lange keine Erfahrung mit neuen Versionen des Ruhezustands. Aber zuvor ohne Reinigung konnten Sie einige unerwartete Ergebnisse erhalten. Also schlage ich vor, verschiedene Ansätze auszuprobieren oder sogar die neueste Dokumentation zu überprüfen
Aleksei Bulgak
80

flush()synchronisiert Ihre Datenbank mit dem aktuellen Status von Objekten im Speicher, schreibt die Transaktion jedoch nicht fest. Wenn Sie also nach dem flush()Aufruf eine Ausnahme erhalten , wird die Transaktion zurückgesetzt. Sie können Ihre Datenbank mit kleinen Datenblöcken synchronisieren, flush()anstatt große Daten auf einmal zu übertragen, commit()und das Risiko eingehen, eine zu erhalten OutOfMemoryException.

commit()macht die in der Datenbank gespeicherten Daten dauerhaft. Es gibt keine Möglichkeit, Ihre Transaktion zurückzusetzen, sobald dies commit()erfolgreich ist.

Anand Kulkarni
quelle
54

Ein häufiger Fall für explizites Leeren ist, wenn Sie eine neue persistente Entität erstellen und möchten, dass ihr ein künstlicher Primärschlüssel generiert und zugewiesen wird, damit Sie ihn später in derselben Transaktion verwenden können. In diesem Fall würde das Aufrufen von Flush dazu führen, dass Ihrer Entität eine ID zugewiesen wird.

Ein anderer Fall ist, wenn der Cache der ersten Ebene viele Dinge enthält und Sie ihn regelmäßig löschen möchten (um den vom Cache verwendeten Speicherplatz zu reduzieren), Sie aber trotzdem das Ganze zusammenschreiben möchten . Dies ist der Fall, den Alekseis Antwort abdeckt.

Nathan Hughes
quelle
1
Wenn Sie sofort Zugriff auf die generierte PK haben möchten, müssen Sie meiner Meinung nach auch anrufen.refresh(...)
Sam Berry
12

flush();Beim Flushing wird der zugrunde liegende persistente Speicher mit dem im Speicher gespeicherten persistenten Status synchronisiert. Es wird in der laufenden Transaktion aktualisiert oder in Ihre Tabellen eingefügt, diese Änderungen werden jedoch möglicherweise nicht festgeschrieben.

Sie müssen die Stapelverarbeitung leeren, da dies sonst zu OutOfMemoryException führen kann.

Commit();Beim Festschreiben wird die Datenbank festgeschrieben. Wenn Sie ein dauerhaftes Objekt haben und einen Wert darauf ändern, wird es verschmutzt und der Ruhezustand muss diese Änderungen in Ihre Persistenzschicht übertragen. Sie sollten sich also verpflichten, aber es beendet auch die Arbeitseinheit ( transaction.commit()).

Ashu
quelle
8

Es wird normalerweise nicht empfohlen, Flush explizit aufzurufen, es sei denn, dies ist erforderlich. Im Ruhezustand ruft Flush normalerweise am Ende der Transaktion automatisch auf, und wir sollten es funktionieren lassen. In einigen Fällen müssen Sie möglicherweise explizit Flush aufrufen, wobei eine zweite Aufgabe vom Ergebnis der ersten Persistenzaufgabe abhängt, die sich beide in derselben Transaktion befinden.

Beispielsweise müssen Sie möglicherweise eine neue Entität beibehalten und dann die ID dieser Entität verwenden, um eine andere Aufgabe innerhalb derselben Transaktion auszuführen. In diesem Fall muss die Entität zuerst explizit geleert werden.

@Transactional
void someServiceMethod(Entity entity){
    em.persist(entity); 
    em.flush() //need to explicitly flush in order to use id in next statement
    doSomeThingElse(entity.getId());    
}

Beachten Sie außerdem, dass das explizite Leeren kein Datenbank-Commit verursacht. Ein Datenbank-Commit wird nur am Ende einer Transaktion durchgeführt. Wenn also nach dem Aufruf von Flush ein Laufzeitfehler auftritt, werden die Änderungen weiterhin rückgängig gemacht.

adn.911
quelle
4

Standardmäßig ist der Flush-Modus AUTO. Dies bedeutet: "Die Sitzung wird manchmal vor der Ausführung der Abfrage geleert, um sicherzustellen, dass Abfragen niemals den veralteten Status zurückgeben." Die Sitzung wird jedoch meistens geleert, wenn Sie Ihre Änderungen festschreiben. Der manuelle Aufruf der Flush-Methode ist nützlich, wenn Sie FlushMode = MANUAL verwenden oder eine Optimierung durchführen möchten. Aber ich habe das noch nie gemacht, deshalb kann ich Ihnen keine praktischen Ratschläge geben.

dimas
quelle
2

session.flush () ist eine Synchronisierungsmethode, mit der Daten nacheinander in die Datenbank eingefügt werden. Wenn wir diese Methode verwenden, werden Daten nicht in der Datenbank gespeichert, sondern im Cache. Wenn in der Mitte eine Ausnahme auftritt, können wir damit umgehen. Commit () speichert jedoch Daten in der Datenbank. Wenn wir dann mehr Daten speichern, besteht möglicherweise die Möglichkeit, dass die Speicherausnahme ausfällt, wie im JDBC-Programm im Thema Speicherpunkt

Gautam Prusty
quelle