Bisher war es meine Präferenz, immer EntityManager zu verwenden merge()
, um sowohl das Einfügen als auch das Aktualisieren zu erledigen. Ich habe jedoch auch festgestellt, dass beim Zusammenführen vor dem Aktualisieren / Einfügen zusätzliche Auswahlabfragen ausgeführt werden, um sicherzustellen, dass der Datensatz noch nicht in der Datenbank vorhanden ist.
Jetzt arbeite ich an einem Projekt, das umfangreiche (Massen-) Einfügungen in die Datenbank erfordert. Ist es aus Sicht der Leistung sinnvoll, in einem Szenario, in dem ich absolut weiß, dass ich immer eine neue Instanz von Objekten erstelle, die beibehalten werden sollen, persist anstelle von merge zu verwenden?
Ich würde auf jeden Fall mit beharrlich gehen,
persist()
wenn, wie Sie sagten:Darum geht es bei dieser Methode - sie schützt Sie in Fällen, in denen die Entität bereits vorhanden ist (und setzt Ihre Transaktion zurück).
quelle
RuntimeException
definitiv keine gute Praxis (aber ich nehme an, Sie haben es gemeintEntityExistsException
). Ich würde es nicht als universelle gute Codierungspraxis bezeichnen . Das hängt von Ihren Anforderungen ab. Wenn die Anforderungen sagen , dass das Objekt muss beibehalten werden und es darf nicht vorhanden sein , bevor diese Aktion stattfindet - ich würde auf jeden Fall nicht versuchen merge zu tun , nachdem Ausnahme zu kontrollieren. Wenn Sie den JTA-Entitätsmanager verwenden, wird Ihre Transaktion zu diesem Zeitpunkt bereits für das Rollback markiert.persist
eine bereits vorhandene Entität aufrufen , erhalten Sie dieseEntityExistsException
und aufgrund des JPA-Implementierers wird diese Transaktion zurückgesetzt (nicht, weil es sich um eine Laufzeitausnahme handelt). Mit anderen Worten - ich denke (nicht sicher), dass selbst wenn Sie diese Ausnahme versuchen / abfangen, der TX weiterhin für den Rollback markiert wird. Dermerge
wird niemals werfenEntityExistsException
.Wenn Sie den zugewiesenen Generator verwenden, kann die Verwendung von
merge
anstelle vonpersist
eine redundante SQL-Anweisung verursachen und somit die Leistung beeinträchtigen.Das Aufrufen der Zusammenführung für verwaltete Entitäten ist ebenfalls ein Fehler, da verwaltete Entitäten automatisch von Hibernate verwaltet werden und ihr Status beim Löschen des Persistenzkontexts durch den Dirty-Checking-Mechanismus mit dem Datenbankdatensatz synchronisiert wird .
Um zu verstehen, wie dies alles funktioniert, sollten Sie zunächst wissen, dass Hibernate die Entwickler-Denkweise von SQL-Anweisungen zu Entitätsstatusübergängen verschiebt .
Sobald eine Entität von Hibernate aktiv verwaltet wird, werden alle Änderungen automatisch an die Datenbank weitergegeben.
Der Ruhezustand überwacht derzeit angeschlossene Entitäten. Damit eine Entität verwaltet werden kann, muss sie sich im richtigen Entitätsstatus befinden.
Zunächst müssen wir alle Entitätszustände definieren:
Neu (vorübergehend)
Ein neu erstelltes Objekt, das noch nie einem Ruhezustand
Session
(akaPersistence Context
) zugeordnet wurde und keiner Datenbanktabellenzeile zugeordnet ist, befindet sich im Status Neu (vorübergehend).Um persistent zu werden, müssen wir entweder die
EntityManager#persist
Methode explizit aufrufen oder den transitiven Persistenzmechanismus verwenden.Dauerhaft (verwaltet)
Eine persistente Entität wurde einer Datenbanktabellenzeile zugeordnet und wird vom aktuell ausgeführten Persistenzkontext verwaltet. Jede an dieser Entität vorgenommene Änderung wird erkannt und an die Datenbank weitergegeben (während der Sitzungsspülzeit). Mit Hibernate müssen wir keine INSERT / UPDATE / DELETE-Anweisungen mehr ausführen. Der Ruhezustand verwendet einen Transaktions-Write-Behind- Arbeitsstil und Änderungen werden im allerletzten verantwortlichen Moment während der aktuellen
Session
Spülzeit synchronisiert .Löste sich
Sobald der aktuell ausgeführte Persistenzkontext geschlossen ist, werden alle zuvor verwalteten Entitäten getrennt. Aufeinanderfolgende Änderungen werden nicht mehr verfolgt und es findet keine automatische Datenbanksynchronisierung statt.
Um eine getrennte Entität einer aktiven Ruhezustandssitzung zuzuordnen, können Sie eine der folgenden Optionen auswählen:
Wiederanbringen
Der Ruhezustand (aber nicht JPA 2.1) unterstützt das erneute Anhängen über die Aktualisierungsmethode "Sitzung #". Eine Ruhezustandssitzung kann nur ein Entitätsobjekt für eine bestimmte Datenbankzeile zuordnen. Dies liegt daran, dass der Persistenzkontext als speicherinterner Cache (Cache der ersten Ebene) fungiert und einem bestimmten Schlüssel (Entitätstyp und Datenbankkennung) nur ein Wert (Entität) zugeordnet ist. Eine Entität kann nur dann erneut zugeordnet werden, wenn der aktuellen Ruhezustandssitzung noch kein anderes JVM-Objekt (das mit derselben Datenbankzeile übereinstimmt) bereits zugeordnet ist.
Zusammenführen
Durch die Zusammenführung wird der Status der getrennten Entität (Quelle) in eine Instanz einer verwalteten Entität (Ziel) kopiert. Wenn die zusammengeführte Entität in der aktuellen Sitzung keine Entsprechung hat, wird eine aus der Datenbank abgerufen. Die Instanz des getrennten Objekts bleibt auch nach dem Zusammenführungsvorgang weiterhin getrennt.
Entfernt
Obwohl JPA verlangt, dass nur verwaltete Entitäten entfernt werden dürfen, kann Hibernate auch getrennte Entitäten löschen (jedoch nur über einen Aufruf der Session # delete-Methode). Eine entfernte Entität ist nur zum Löschen geplant, und die tatsächliche Datenbank-DELETE-Anweisung wird während der Sitzungsspülzeit ausgeführt.
Um die JPA-Statusübergänge besser zu verstehen, können Sie das folgende Diagramm visualisieren:
Oder wenn Sie die Hibernate-spezifische API verwenden:
quelle