JPA EntityManager: Warum persist() statt merge() verwenden?

EntityManager.merge()` kann neue Objekte einfügen und bestehende aktualisieren.

Warum sollte man "persist()" verwenden (das nur neue Objekte erstellen kann)?

Lösung

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 verwaltet (d.h. zukünftige Aktualisierungen der Entität werden verfolgt).

Merge erstellt eine neue Instanz Ihrer Entität, kopiert den Zustand der übergebenen Entität und macht die neue Kopie verwaltet. Die Instanz, die Sie übergeben, wird nicht verwaltet (alle Änderungen, die Sie vornehmen, werden nicht Teil der Transaktion - es sei denn, Sie rufen merge erneut auf).

Vielleicht hilft ein Codebeispiel weiter.

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 man Szenario 2 verwenden sollte.

Kommentare (12)

Mir ist aufgefallen, dass ich bei der Verwendung von "em.merge" für jede "INSERT"-Anweisung eine "SELECT"-Anweisung erhielt, 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 dann nur noch INSERT-Anweisungen.

Kommentare (2)

Ich war immer lazyLoading Ausnahmen auf meine Entität, weil ich versuchte, eine Lazy geladen Sammlung zugreifen, die in Sitzung war.

Was ich tun würde, war in einer separaten Anforderung, die Entität aus der Sitzung abrufen und dann versuchen, eine Sammlung in meiner JSP-Seite zugreifen, die problematisch war.

Um das Problem zu lösen, habe ich dieselbe Entität in meinem Controller aktualisiert und an meine JSP-Seite übergeben, obwohl ich mir vorstelle, dass sie, wenn ich sie erneut in der Sitzung speichere, auch über SessionScope zugänglich ist und keine LazyLoadingException auslöst, eine Änderung von Beispiel 2:

Das Folgende hat bei mir funktioniert:

// scenario 2 MY WAY
// tran starts
e = new MyEntity();
e = em.merge(e); // re-assign to the same entity "e"

//access e from jsp and it will work dandy!!
Kommentare (0)