EntityManager.merge()
kann neue Objekte einfügen und bestehende aktualisieren.
Warum sollte man die persist()
(die nur neue Objekte erstellen kann)?
EntityManager.merge()
kann neue Objekte einfügen und bestehende aktualisieren.
Warum sollte man die persist()
(die nur neue Objekte erstellen kann)?
In beiden Fällen wird eine Entität zu einem PersistenceContext hinzugefügt, der Unterschied liegt darin, was man anschließend mit der Entität macht.
Persist nimmt eine Entitätsinstanz, fügt sie dem Kontext hinzu und macht diese Instanz verwaltbar (d.h. zukünftige Aktualisierungen der Entität werden nachverfolgt).
Merge gibt die verwaltete Instanz zurück, mit der der Zustand zusammengeführt wurde. Es gibt etwas zurück, das im PersistenceContext existiert, oder erstellt eine neue Instanz Ihrer Entität. In jedem Fall wird der Zustand von der übergebenen Entität kopiert und eine verwaltete Kopie zurückgegeben. Die Instanz, die Sie übergeben, wird nicht verwaltet (alle Änderungen, die Sie vornehmen, werden nicht Teil der Transaktion sein - es sei denn, Sie rufen merge erneut auf). Sie können jedoch die zurückgegebene (verwaltete) Instanz verwenden.
Vielleicht hilft ein Codebeispiel.
MyEntity e = new MyEntity();
// scenario 1
// tran starts
em.persist(e);
e.setSomeField(someValue);
// tran ends, and the row for someField is updated in the database
// scenario 2
// tran starts
e = new MyEntity();
em.merge(e);
e.setSomeField(anotherValue);
// tran ends but the row for someField is not updated in the database
// (you made the changes *after* merging)
// scenario 3
// tran starts
e = new MyEntity();
MyEntity e2 = em.merge(e);
e2.setSomeField(anotherValue);
// tran ends and the row for someField is updated
// (the changes were made to e2, not e)
Szenario 1 und 3 sind ungefähr gleichwertig, aber es gibt einige Situationen, in denen Sie Szenario 2 verwenden sollten.
Persistieren und Zusammenführen dienen zwei verschiedenen Zwecken (sie sind überhaupt keine Alternativen).
(bearbeitet, um Informationen über Unterschiede zu erweitern)
beharrlich:
verschmelzen:
persist() Effizienz:
persist()-Semantik:
Beispiel:
{
AnyEntity newEntity;
AnyEntity nonAttachedEntity;
AnyEntity attachedEntity;
// Create a new entity and persist it
newEntity = new AnyEntity();
em.persist(newEntity);
// Save 1 to the database at next flush
newEntity.setValue(1);
// Create a new entity with the same Id than the persisted one.
AnyEntity nonAttachedEntity = new AnyEntity();
nonAttachedEntity.setId(newEntity.getId());
// Save 2 to the database at next flush instead of 1!!!
nonAttachedEntity.setValue(2);
attachedEntity = em.merge(nonAttachedEntity);
// This condition returns true
// merge has found the already attached object (newEntity) and returns it.
if(attachedEntity==newEntity) {
System.out.print("They are the same object!");
}
// Set 3 to value
attachedEntity.setValue(3);
// Really, now both are the same object. Prints 3
System.out.println(newEntity.getValue());
// Modify the un attached object has no effect to the entity manager
// nor to the other objects
nonAttachedEntity.setValue(42);
}
Auf diese Weise existiert nur 1 angehängtes Objekt für jedes Register im Entity Manager.
merge() für eine Entität mit einer id ist etwa so:
AnyEntity myMerge(AnyEntity entityToSave) {
AnyEntity attached = em.find(AnyEntity.class, entityToSave.getId());
if(attached==null) {
attached = new AnyEntity();
em.persist(attached);
}
BeanUtils.copyProperties(attached, entityToSave);
return attached;
}
Obwohl merge() bei einer Verbindung mit MySQL so effizient sein könnte wie persist() unter Verwendung eines Aufrufs von INSERT mit der Option ON DUPLICATE KEY UPDATE, ist JPA eine Programmierung auf sehr hohem Niveau und man kann nicht davon ausgehen, dass dies überall der Fall sein wird.
Können Sie einen Fall nennen, in dem es nicht zulässig ist, die em.persist(x)
con x = em.merge(x)
?
Persist() kann eine EntityExistsException auslösen. Wenn Sie sicher sein wollen, dass Ihr Code eine Einfügung und nicht eine Aktualisierung der Daten vornimmt, müssen Sie persist verwenden.
Wenn Sie den zugewiesenen Generator verwenden, müssen Sie merge
anstelle von persist
kann zu einer redundanten SQL-Anweisung führen und damit die Leistung beeinträchtigen.
Auch das Anrufen merge
für verwaltete Entitäten ist ebenfalls ein Fehler, da verwaltete Entitäten automatisch von Hibernate verwaltet werden und ihr Zustand durch den Dirty-Checking-Mechanismus beim Flushen des Persistenzkontextes mit dem Datenbankeintrag synchronisiert wird.
Um zu verstehen, wie das alles funktioniert, sollten Sie zunächst wissen, dass Hibernate die Denkweise der Entwickler von SQL-Anweisungen auf Zustandsübergänge von Entitäten verlagert.
Sobald eine Entität aktiv von Hibernate verwaltet wird, werden alle Änderungen automatisch an die Datenbank weitergegeben.
Hibernate überwacht aktuell angehängte Entitäten. Damit eine Entität verwaltet werden kann, muss sie sich jedoch im richtigen Entitätsstatus befinden.
Um die JPA-Zustandsübergänge besser zu verstehen, können Sie sich das folgende Diagramm ansehen:
Oder wenn Sie die Hibernate-spezifische API verwenden:
Wie in den obigen Diagrammen dargestellt, kann eine Entität einen der folgenden vier Zustände einnehmen:
Ein neu erstelltes Objekt, das noch nie mit einem Hibernate Session
(a.k.a. Persistence Context
) und keiner Datenbanktabellenzeile zugeordnet ist, befindet sich im Zustand Neu (transient).
Um persistent zu werden, müssen wir entweder explizit die EntityManager#persist
Methode oder verwenden Sie den transitiven Persistenzmechanismus.
Dauerhaft (verwaltet)
Eine persistente Entität wurde mit einer Datenbanktabellenzeile verknüpft und wird durch den aktuell laufenden Persistenzkontext verwaltet. Jede Änderung, die an einer solchen Entität vorgenommen wird, wird erkannt und an die Datenbank weitergegeben (während der Session-Flush-Zeit). Mit Hibernate müssen wir keine INSERT/UPDATE/DELETE-Anweisungen mehr ausführen. Hibernate verwendet einen transaktionalen Write-Behind-Arbeitsstil, und Änderungen werden im allerletzten verantwortlichen Moment synchronisiert, während der aktuellen Session
Spülungszeit.
Freistehend
Sobald der aktuell laufende Persistenzkontext geschlossen wird, werden alle zuvor verwalteten Entitäten abgetrennt. Aufeinanderfolgende Änderungen werden nicht mehr verfolgt und es findet keine automatische Datenbanksynchronisation statt.
Um eine abgetrennte Entität mit einer aktiven Hibernate-Sitzung zu verknüpfen, können Sie eine der folgenden Optionen wählen:
Wiederbefestigung
Hibernate (aber nicht JPA 2.1) unterstützt die Wiederanbindung durch die Methode Session#update.
Eine Hibernate-Sitzung kann nur ein Entity-Objekt für eine bestimmte Datenbankzeile zuordnen. Dies liegt daran, dass der Persistenzkontext als In-Memory-Cache (Cache der ersten Ebene) fungiert und nur ein Wert (Entität) mit einem bestimmten Schlüssel (Entitätstyp und Datenbankkennung) verbunden ist.
Eine Entität kann nur dann wieder angehängt werden, wenn es kein anderes JVM-Objekt (das derselben Datenbankzeile entspricht) gibt, das bereits mit der aktuellen Hibernate-Sitzung verbunden ist.
Zusammenführung
Bei der Zusammenführung wird der Zustand der abgetrennten Entität (Quelle) in eine verwaltete Entitätsinstanz (Ziel) kopiert. Wenn die zusammenführende Entität keine Entsprechung in der aktuellen Sitzung hat, wird eine aus der Datenbank geholt.
Die losgelöste Objektinstanz bleibt auch nach dem Zusammenführungsvorgang losgelöst.
entfernen
Obwohl JPA vorschreibt, dass nur verwaltete Entitäten entfernt werden dürfen, kann Hibernate auch losgelöste Entitäten löschen (allerdings nur durch einen Aufruf der Methode Session#delete).
Eine entfernte Entität wird nur zur Löschung eingeplant und die eigentliche DELETE-Anweisung der Datenbank wird während des Session Flush ausgeführt.
Ihr Artikel über die Betriebsordnung im Normalfall. Meine Frage speziell für orphanRemoval
Überprüfen Sie meine Antwort . Es gibt nichts Magisches, was Hibernate hier tun sollte. Sie müssen nur den richtigen Code für die Datenzugriffslogik schreiben.
Ich habe festgestellt, dass ich bei der Verwendung von em.merge
Ich habe eine SELECT
Anweisung für jede INSERT
selbst wenn es kein Feld gab, das JPA für mich generierte - das Primärschlüsselfeld war eine UUID, die ich selbst festgelegt hatte. Ich wechselte zu em.persist(myEntityObject)
und bekam gerade INSERT
Aussagen dann.
Das ist sinnvoll, da Sie die IDs zuweisen und der JPA-Container keine Ahnung hat, woher Sie diese haben. Es besteht eine (kleine) Chance, dass das Objekt bereits in der Datenbank vorhanden ist, z. B. in einem Szenario, in dem mehrere Anwendungen in dieselbe Datenbank schreiben.
Ich hatte ein ähnliches Problem mit merge()
. Ich hatte PostgreSQL-Datenbank mit komplizierten siehe Die Ansicht aggregierte Daten aus mehreren Tabellen (die Tabellen hatten eine identische Struktur, aber unterschiedliche Namen). Also versuchte JPA zu tun merge()
aber eigentlich hat JPA erst einmal SELECT
(Datenbank konnte aufgrund von View-Einstellungen mehrere Datensätze mit demselben Primärschlüssel aus verschiedenen Tabellen zurückgeben!), dann schlug JPA (Hibernate war eine Implementierung) fehl: es gibt mehrere Datensätze mit demselben Schlüssel ( org.hibernate.HibernateException: More than one row with the given identifier was found
). In meinem Fall persist()
hat mir geholfen.
Die JPA-Spezifikation sagt Folgendes über persist()
.
Si X ein losgelöstes Objekt ist, wird die
EntityExistsException
kann ausgelöst werden, wenn die persistente Operation aufgerufen wird, oder dieEntityExistsException
oder eine anderePersistenceException
kann beim Flush- oder Commit-Zeitpunkt geworfen werden.
Also mit persist()
wäre geeignet, wenn das Objekt sollte nicht ein losgelöstes Objekt zu sein. Sie könnten es vorziehen, dass der Code die PersistenceException
so dass es schnell scheitert.
Obwohl die Spezifikation ist unklar , persist()
könnte die @GeneratedValue
@Id
für ein Objekt. merge()
muss jedoch ein Objekt mit der Eigenschaft @Id
bereits erzeugt.
+1 für " merge()
muss jedoch ein Objekt mit der Eigenschaft @Id
bereits erzeugt . ". Wann immer der EntityManager keinen Wert für das Feld der Objekt-ID findet, wird dieser in die DB persistiert (eingefügt).
Ich habe das zuerst nicht verstanden, weil ich mir über die Staaten nicht im Klaren war. Ich hoffe, das hilft jemandem, so wie es bei mir der Fall war. docs.jboss.org/hibernate/core/3.6/reference/de-US/html/
CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.
14 Stimmen
techblog.bozho.net/?p=266 zugehörige
2 Stimmen
Wenn Sie Diagramme mögen. Siehe dies: spitballer.blogspot.in/2010/04/