Hier ist mein Verständnis der Methoden. Hauptsächlich basieren diese jedoch auf der API, da ich in der Praxis nicht alle verwende.
saveOrUpdate Ruft
abhängig von einigen Überprüfungen entweder Speichern oder Aktualisieren auf. Wenn beispielsweise keine Kennung vorhanden ist, wird save aufgerufen. Andernfalls wird das Update aufgerufen.
Speichern
Behält eine Entität bei. Weist eine Kennung zu, wenn keine vorhanden ist. Wenn ja, wird im Wesentlichen ein Update durchgeführt. Gibt die generierte ID der Entität zurück.
update
Versucht, die Entität unter Verwendung einer vorhandenen Kennung beizubehalten. Wenn keine Kennung vorhanden ist, wird meiner Meinung nach eine Ausnahme ausgelöst.
saveOrUpdateCopy
Dies ist veraltet und sollte nicht mehr verwendet werden. Stattdessen gibt es ...
verschmelzen
Hier beginnt mein Wissen ins Stocken zu geraten. Das Wichtigste dabei ist der Unterschied zwischen vorübergehenden, getrennten und beständigen Entitäten. Weitere Informationen zu den Objektzuständen finden Sie hier . Mit Speichern und Aktualisieren haben Sie es mit persistenten Objekten zu tun. Sie sind mit einer Sitzung verknüpft, damit der Ruhezustand weiß, was sich geändert hat. Wenn Sie jedoch ein vorübergehendes Objekt haben, ist keine Sitzung beteiligt. In diesen Fällen müssen Sie Merge für Updates verwenden und zum Speichern beibehalten.
persist
Wie oben erwähnt, wird dies für vorübergehende Objekte verwendet. Die generierte ID wird nicht zurückgegeben.
quelle
update
Ein vorübergehendes Objekt ist in Ordnung, ich habe keine Ausnahme erhalten.Im Hibernate-Forum finden Sie eine Erklärung der subtilen Unterschiede zwischen Persist und Save. Es sieht so aus, als ob der Unterschied die Zeit ist, zu der die INSERT-Anweisung letztendlich ausgeführt wird. Da save den Bezeichner zurückgibt, muss die INSERT-Anweisung unabhängig vom Status der Transaktion sofort ausgeführt werden (was im Allgemeinen eine schlechte Sache ist). Persist führt keine Anweisungen außerhalb der aktuell ausgeführten Transaktion aus, nur um den Bezeichner zuzuweisen. Speichern / Behalten arbeiten beide mit vorübergehenden Instanzen , dh Instanzen, denen noch keine Kennung zugewiesen wurde und die als solche nicht in der Datenbank gespeichert werden.
Update und Merge funktionieren beide für getrennte Instanzen , dh Instanzen, die einen entsprechenden Eintrag in der Datenbank haben, aber derzeit nicht an eine Sitzung angehängt (oder von dieser verwaltet) sind. Der Unterschied zwischen ihnen besteht darin, was mit der Instanz passiert, die an die Funktion übergeben wird. update versucht, die Instanz erneut zuzuordnen. Dies bedeutet, dass derzeit keine andere Instanz der persistenten Entität an die Sitzung angehängt sein darf. Andernfalls wird eine Ausnahme ausgelöst. Beim Zusammenführen werden jedoch nur alle Werte in eine persistente Instanz in der Sitzung kopiert (die geladen wird, wenn sie derzeit nicht geladen ist). Das Eingabeobjekt wird nicht geändert. Das Zusammenführen ist also allgemeiner als das Aktualisieren, kann aber mehr Ressourcen verbrauchen.
quelle
save() - If an INSERT has to be executed to get the identifier, then this INSERT happens immediately, no matter if you are inside or outside of a transaction. This is problematic in a long-running conversation with an extended Session/persistence context.
Können Sie mir bitte sagen, wie eine Einfügung außerhalb einer Sitzung erfolgen kann und warum sie schlecht ist?INSERT
bearbeitet wird. Folglich können Sie in diesen Fällen einen Bezeichner jetzt nicht zurückgeben, ohne ihn generiert zu haben, und um ihn zu generieren, müssen Sie ihnINSERT
sofort ausführen . Da eine Transaktion mit langer Laufzeit derzeit nicht ausgeführt wird, sondern nur beim Festschreiben, besteht die einzige Möglichkeit, die Transaktion jetzt auszuführenINSERT
, darin, sie außerhalb des Sendevorgangs auszuführen .Dieser Link erklärt auf gute Weise:
http://www.stevideter.com/2008/12/07/saveorupdate-versus-merge-in-hibernate/
Wir alle haben diese Probleme, auf die wir nur selten genug stoßen, dass wir, wenn wir sie wiedersehen, wissen, dass wir sie gelöst haben, uns aber nicht erinnern können, wie.
Die NonUniqueObjectException, die bei Verwendung von Session.saveOrUpdate () im Ruhezustand ausgelöst wird, ist eine von mir. Ich werde einer komplexen Anwendung neue Funktionen hinzufügen. Alle meine Unit-Tests funktionieren einwandfrei. Beim Testen der Benutzeroberfläche und beim Versuch, ein Objekt zu speichern, wird eine Ausnahme mit der Meldung angezeigt, dass der Sitzung bereits ein anderes Objekt mit demselben Bezeichnerwert zugeordnet wurde. Hier ist ein Beispielcode aus Java Persistence with Hibernate.
Um die Ursache dieser Ausnahme zu verstehen, ist es wichtig, die getrennten Objekte zu verstehen und zu verstehen, was passiert, wenn Sie saveOrUpdate () (oder einfach update ()) für ein getrenntes Objekt aufrufen.
Wenn wir eine einzelne Ruhezustandssitzung schließen, werden die persistenten Objekte, mit denen wir arbeiten, getrennt. Dies bedeutet, dass sich die Daten noch im Speicher der Anwendung befinden, der Ruhezustand jedoch nicht mehr für die Verfolgung von Änderungen an den Objekten verantwortlich ist.
Wenn wir dann unser getrenntes Objekt ändern und es aktualisieren möchten, müssen wir das Objekt erneut anbringen. Während dieses erneuten Anbringens überprüft Hibernate, ob weitere Kopien desselben Objekts vorhanden sind. Wenn es welche findet, muss es uns sagen, dass es nicht mehr weiß, was die "echte" Kopie ist. Möglicherweise wurden andere Änderungen an den anderen Kopien vorgenommen, von denen wir erwarten, dass sie gespeichert werden, aber Hibernate weiß nichts über sie, da sie zu diesem Zeitpunkt nicht verwaltet wurden.
Anstatt möglicherweise fehlerhafte Daten zu speichern, informiert uns Hibernate über die NonUniqueObjectException über das Problem.
Was sollen wir also tun? In Hibernate 3 haben wir merge () (in Hibernate 2 verwenden Sie saveOrUpdateCopy ()). Diese Methode zwingt den Ruhezustand, alle Änderungen von anderen getrennten Instanzen auf die zu speichernde Instanz zu kopieren, und führt somit alle Änderungen im Speicher vor dem Speichern zusammen.
Es ist wichtig zu beachten, dass beim Zusammenführen ein Verweis auf die neu aktualisierte Version der Instanz zurückgegeben wird. Es wird kein Element erneut an die Sitzung angehängt. Wenn Sie beispielsweise die Gleichheit testen (item == item3), wird in diesem Fall false zurückgegeben. Sie werden wahrscheinlich von diesem Punkt an mit item3 arbeiten wollen.
Es ist auch wichtig zu beachten, dass die Java Persistence API (JPA) kein Konzept für getrennte und erneut angehängte Objekte hat und EntityManager.persist () und EntityManager.merge () verwendet.
Ich habe im Allgemeinen festgestellt, dass saveOrUpdate () bei Verwendung von Hibernate normalerweise für meine Anforderungen ausreicht. Normalerweise muss ich Merge nur verwenden, wenn ich Objekte habe, die Verweise auf Objekte desselben Typs haben können. Zuletzt lag die Ursache der Ausnahme im Code, der bestätigte, dass die Referenz nicht rekursiv war. Ich habe dasselbe Objekt im Rahmen der Validierung in meine Sitzung geladen und den Fehler verursacht.
Wo sind Sie auf dieses Problem gestoßen? Hat Merge für Sie funktioniert oder brauchten Sie eine andere Lösung? Verwenden Sie lieber immer die Zusammenführung oder bevorzugen Sie es nur, wenn dies für bestimmte Fälle erforderlich ist
quelle
Tatsächlich hängt der Unterschied zwischen Ruhezustand
save()
undpersist()
Methoden von der von uns verwendeten Generatorklasse ab.Wenn unsere Generatorklasse zugewiesen ist, gibt es keinen Unterschied zwischen
save()
undpersist(
Methoden. Da Generator 'zugewiesen' bedeutet, müssen wir als Programmierer den Primärschlüsselwert angeben, der in der Datenbank gespeichert werden soll. [Hoffe, Sie kennen dieses Generatorkonzept] Nehmen Sie bei einer anderen als der zugewiesenen Generatorklasse an, wenn unser Generatorklassenname Inkrement bedeutet Der Ruhezustand selbst weist den Primärschlüssel-ID-Wert in das Datenbankrecht ein [außer dem zugewiesenen Generator wird der Ruhezustand nur verwendet, um den Primärschlüssel-ID-Wert zu berücksichtigen]. In diesem Fall wird der Datensatz in den Fallsave()
oder diepersist()
Methode eingefügt Die Datenbank ist normal. Aber hören Sie, diesave()
Methode kann den Primärschlüssel-ID-Wert zurückgeben, der im Ruhezustand generiert wird, und wir können ihn sehenIn diesem Fall
persist()
wird dem Client niemals ein Wert zurückgegeben.quelle
Ich habe ein gutes Beispiel gefunden, das die Unterschiede zwischen allen Speichermethoden im Ruhezustand zeigt:
http://www.journaldev.com/3481/hibernate-session-merge-vs-update-save-saveorupdate-persist-example
Kurz gesagt, gemäß dem obigen Link:
sparen()
fortdauern()
saveOrUpdate ()
Kann mit oder ohne Transaktion verwendet werden, und genau wie save (), wenn es ohne die Transaktion verwendet wird, werden zugeordnete Entitäten nicht gespeichert, es sei denn, wir leeren die Sitzung.
Ergebnisse in Einfüge- oder Aktualisierungsabfragen basierend auf den bereitgestellten Daten. Wenn die Daten in der Datenbank vorhanden sind, wird die Aktualisierungsabfrage ausgeführt.
aktualisieren()
verschmelzen()
Praktische Beispiele für all dies finden Sie unter dem oben erwähnten Link. Es zeigt Beispiele für all diese verschiedenen Methoden.
quelle
Wie ich in diesem Artikel erklärt habe , sollten Sie die JPA-Methoden die meiste Zeit bevorzugen, und die
update
für Stapelverarbeitungsaufgaben .Eine JPA- oder Hibernate-Entität kann sich in einem der folgenden vier Zustände befinden:
Der Übergang von einem Status in den anderen erfolgt über die Methoden EntityManager oder Session.
Beispielsweise stellt der JPA
EntityManager
die folgenden Entitätsstatusübergangsmethoden bereit.Die Ruhe
Session
implementiert alle JPAEntityManager
Methoden und bietet einige zusätzliche Entität Zustandsübergangsverfahren wiesave
,saveOrUpdate
undupdate
.Fortdauern
Um den Status einer Entität von Transient (Neu) in Verwaltet (Persistent) zu ändern, können Sie die
persist
von der JPA angebotene Methode verwenden, die auch vom RuhezustandEntityManager
geerbt wirdSession
.Daher bei der Ausführung des folgenden Testfalls:
Der Ruhezustand generiert die folgenden SQL-Anweisungen:
Beachten Sie, dass das
id
zugewiesen wird, bevor dieBook
Entität an den aktuellen Persistenzkontext angehängt wird. Dies ist erforderlich, da die verwalteten Entitäten in einerMap
Struktur gespeichert sind, in der der Schlüssel aus dem Entitätstyp und seiner Kennung besteht und der Wert die Entitätsreferenz ist. Dies ist der Grund, warum die JPAEntityManager
und der WinterschlafSession
als First-Level-Cache bezeichnet werden.Beim Aufruf
persist
wird die Entität nur an den aktuell ausgeführten Persistenzkontext angehängt, und das INSERT kann bis zum verschoben werdenflush
aufgerufen wird.Die einzige Ausnahme ist der IDENTITY-Generator, der das INSERT sofort auslöst, da nur so die Entitätskennung abgerufen werden kann. Aus diesem Grund kann Hibernate mithilfe des IDENTITY-Generators keine Batch-Einfügungen für Entitäten durchführen. Weitere Informationen zu diesem Thema finden Sie in diesem Artikel .
sparen
Die Hibernate-spezifische
save
Methode ist älter als JPA und seit Beginn des Hibernate-Projekts verfügbar.save
Betrachten Sie den folgenden Testfall, um zu sehen, wie die Methode funktioniert:Wenn Sie den obigen Testfall ausführen, generiert Hibernate die folgenden SQL-Anweisungen:
Wie Sie sehen können, ist das Ergebnis identisch mit dem
persist
Methodenaufruf. Im Gegensatz dazupersist
gibt diesave
Methode jedoch die Entitätskennung zurück.Weitere Informationen finden Sie in diesem Artikel .
Aktualisieren
Die Hibernate-spezifische
update
Methode soll den Dirty-Checking-Mechanismus umgehen und eine Entitätsaktualisierung zum Flush-Zeitpunkt erzwingen.Um zu sehen, wie die
update
Methode funktioniert, betrachten Sie das folgende Beispiel, in dem eineBook
Entität in einer Transaktion beibehalten wird. Anschließend wird sie geändert, während sich die Entität im getrennten Zustand befindet, und das SQL-UPDATE wird mithilfe desupdate
Methodenaufrufs erzwungen.Bei der Ausführung des obigen Testfalls generiert Hibernate die folgenden SQL-Anweisungen:
Beachten Sie, dass das
UPDATE
während des Persistence Context Flushs unmittelbar vor dem Festschreiben ausgeführt wird. Deshalb wird dieUpdating the Book entity
Nachricht zuerst protokolliert.Verwenden
@SelectBeforeUpdate
, um unnötige Updates zu vermeidenJetzt wird das UPDATE immer ausgeführt, auch wenn die Entität im getrennten Zustand nicht geändert wurde. Um dies zu verhindern, können Sie die
@SelectBeforeUpdate
Annotation Hibernate verwenden, die eineSELECT
abgerufene Anweisung auslöstloaded state
die dann vom Dirty-Checking-Mechanismus verwendet wird.Wenn wir also die
Book
Entität mit der@SelectBeforeUpdate
Annotation versehen:Führen Sie den folgenden Testfall aus:
Hibernate führt die folgenden SQL-Anweisungen aus:
Beachten Sie, dass diesmal keine
UPDATE
Ausführung erfolgt, da der Mechanismus für die Überprüfung des Ruhezustands im Ruhezustand festgestellt hat, dass die Entität nicht geändert wurde.SaveOrUpdate
Die Hibernate-spezifische
saveOrUpdate
Methode ist nur ein Alias fürsave
undupdate
.Jetzt können Sie verwenden,
saveOrUpdate
wenn Sie eine Entität beibehalten oder eine erzwingen möchten,UPDATE
wie im folgenden Beispiel dargestellt.Vorsicht vor dem
NonUniqueObjectException
Ein Problem, das bei und auftreten
save
kannupdate
,saveOrUpdate
besteht darin, dass der Persistenzkontext bereits eine Entitätsreferenz mit derselben ID und demselben Typ wie im folgenden Beispiel enthält:Wenn Sie den obigen Testfall ausführen, wird Hibernate a auslösen,
NonUniqueObjectException
da die zweiteEntityManager
bereits eineBook
Entität mit derselben Kennung enthält wie die, an die wir übergebenupdate
, und der Persistenzkontext nicht zwei Darstellungen derselben Entität enthalten kann.Verschmelzen
Um dies zu vermeiden
NonUniqueObjectException
, müssen Siemerge
die von der JPA angeboteneEntityManager
und auch vom Ruhezustand geerbte Methode verwendenSession
.Wie in diesem Artikel erläutert ,
merge
ruft der Benutzer einen neuen Entitätsschnappschuss aus der Datenbank ab, wenn im Persistenzkontext keine Entitätsreferenz gefunden wird, und kopiert den Status der getrennten Entität, die an diemerge
Methode übergeben wurde.Um zu sehen, wie die
merge
Methode funktioniert, betrachten Sie das folgende Beispiel, in dem eineBook
Entität in einer Transaktion beibehalten wird. Anschließend wird sie geändert, während sich die Entität im getrennten Zustand befindet, und die getrennte Entitätmerge
in einem Persistenzkontext der Teilsequenz übergeben.Beim Ausführen des obigen Testfalls hat Hibernate die folgenden SQL-Anweisungen ausgeführt:
Beachten Sie, dass sich die von zurückgegebene Entitätsreferenz von der getrennten
merge
unterscheidet, die wir an diemerge
Methode übergeben haben.Obwohl Sie
merge
beim Kopieren des Status der getrennten Entität die Verwendung von JPA bevorzugen sollten , kann das ExtraSELECT
beim Ausführen einer Stapelverarbeitungsaufgabe problematisch sein.Aus diesem Grund sollten Sie die Verwendung bevorzugen,
update
wenn Sie sicher sind, dass dem aktuell ausgeführten Persistenzkontext noch keine Entitätsreferenz zugeordnet ist und die getrennte Entität geändert wurde.Weitere Informationen zu diesem Thema finden Sie in diesem Artikel .
Fazit
Um eine Entität beizubehalten, sollten Sie die JPA-
persist
Methode verwenden. Das Kopieren des Status der getrennten Entitätmerge
sollte bevorzugt werden. Dieupdate
Methode ist nur für Stapelverarbeitungsaufgaben nützlich. Diesave
undsaveOrUpdate
sind nur Aliaseupdate
und Sie sollten sie wahrscheinlich überhaupt nicht verwenden.Einige Entwickler rufen
save
auch dann auf, wenn die Entität bereits verwaltet wird. Dies ist jedoch ein Fehler und löst ein redundantes Ereignis aus, da bei verwalteten Entitäten das UPDATE automatisch zum Zeitpunkt des Löschens des Persistenzkontexts behandelt wird.Weitere Informationen finden Sie in diesem Artikel .
quelle
Beachten Sie, dass beim Aufrufen eines Updates für ein getrenntes Objekt immer ein Update in der Datenbank durchgeführt wird, unabhängig davon, ob Sie das Objekt geändert haben oder nicht. Wenn es nicht Ihren Wünschen entspricht, sollten Sie Session.lock () mit LockMode.None verwenden.
Sie sollten update nur aufrufen, wenn das Objekt außerhalb des Bereichs Ihrer aktuellen Sitzung geändert wurde (im getrennten Modus).
quelle
Keine der folgenden Antworten ist richtig. Alle diese Methoden scheinen einfach gleich zu sein, machen aber in der Praxis absolut unterschiedliche Dinge. Es ist schwer, kurze Kommentare abzugeben. Geben Sie besser einen Link zur vollständigen Dokumentation dieser Methoden an: http://docs.jboss.org/hibernate/core/3.6/reference/en-US/html/objectstate.html
quelle
Keine der obigen Antworten ist vollständig. Obwohl Leo Theobald Antwort am nächsten Antwort aussieht.
Der grundlegende Punkt ist, wie der Ruhezustand mit Zuständen von Entitäten umgeht und wie er mit ihnen umgeht, wenn sich der Zustand ändert. Alles muss auch in Bezug auf Flushes und Commits gesehen werden, was jeder völlig ignoriert zu haben scheint.
Verwenden Sie niemals die Speichermethode von HIBERNATE. VERGESSEN SIE, DASS ES AUCH IM HIBERNATE BESTEHT!
Fortdauern
Wie alle erklärten, wechselt Persist im Grunde genommen eine Entität vom Status "Transient" in den Status "Managed". Zu diesem Zeitpunkt kann ein Slush oder ein Commit eine Insert-Anweisung erstellen. Die Entität bleibt jedoch weiterhin im Status "Verwaltet". Das ändert sich nicht mit Flush.
Wenn Sie zu diesem Zeitpunkt erneut "bestehen", ändert sich nichts. Und es wird keine weiteren Ersparnisse geben, wenn wir versuchen, eine beständige Entität beizubehalten.
Der Spaß beginnt, wenn wir versuchen, die Entität zu vertreiben.
Eine Räumung ist eine spezielle Funktion von Hibernate, die die Entität von "Verwaltet" in "Freistehend" überführt. Wir können keine Persistenz für eine getrennte Entität aufrufen. Wenn wir das tun, löst Hibernate eine Ausnahme aus und die gesamte Transaktion wird beim Festschreiben zurückgesetzt.
Merge vs Update
Dies sind 2 interessante Funktionen, die unterschiedliche Aufgaben ausführen, wenn sie auf unterschiedliche Weise behandelt werden. Beide versuchen, die Entität vom Status "Getrennt" in den Status "Verwaltet" zu überführen. Aber anders machen.
Verstehen Sie eine Tatsache, dass "Losgelöst" eine Art "Offline" -Zustand bedeutet. und verwaltet bedeutet "Online" -Status.
Beachten Sie den folgenden Code:
Wann machst du das? Was denkst du wird passieren? Wenn Sie sagten, dies würde eine Ausnahme auslösen, sind Sie richtig. Dies löst eine Ausnahme aus, da die Zusammenführung für das Entitätsobjekt funktioniert hat, dessen Status getrennt ist. Aber es ändert nichts am Zustand des Objekts.
Hinter den Kulissen löst das Zusammenführen eine Auswahlabfrage aus und gibt im Grunde eine Kopie der Entität zurück, die sich im angehängten Zustand befindet. Beachten Sie den folgenden Code:
Das obige Beispiel funktioniert, weil durch das Zusammenführen eine neue Entität in den Kontext gebracht wurde, der sich im dauerhaften Zustand befindet.
Bei Anwendung mit Update funktioniert dasselbe einwandfrei, da Update keine Kopie einer Entität wie Merge bringt.
Gleichzeitig können wir im Debug-Trace sehen, dass Update keine SQL-Abfrage von select like merge ausgelöst hat.
löschen
Im obigen Beispiel habe ich delete verwendet, ohne über delete zu sprechen. Durch Löschen wird die Entität grundsätzlich vom verwalteten Status in den Status "entfernt" versetzt. Und wenn geleert oder festgeschrieben, wird ein Löschbefehl zum Speichern ausgegeben.
Es ist jedoch möglich, die Entität mithilfe der persist-Methode aus dem Status "entfernt" in den Status "verwaltet" zurückzusetzen.
Hoffe, die obige Erklärung hat alle Zweifel geklärt.
quelle