Frage JPA EntityManager: Warum persist () über merge () verwenden?


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

Warum sollte man benutzen? persist() (Kann nur neue Objekte erstellen)?


839
2017-07-01 16:03


Ursprung


Antworten:


So oder so fügen Sie einem PersistenceContext eine Entity hinzu, der Unterschied liegt darin, was Sie danach mit der Entity machen.

Persist nimmt eine Entitätsinstanz, fügt sie dem Kontext hinzu und macht diese Instanz verwaltet (dh zukünftige Aktualisierungen der Entität werden verfolgt).

Zusammenführen erstellt eine neue Instanz Ihrer Entität, kopiert den Status von der bereitgestellten Entität und erstellt die neue Kopie. Die übergebene Instanz wird nicht verwaltet (Änderungen, die Sie vornehmen, sind nicht Bestandteil der Transaktion - es sei denn, Sie rufen die Zusammenführung erneut auf).

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 in einigen Situationen möchten Sie Szenario 2 verwenden.


1455
2017-07-01 18:28



Persistence und Merge sind für zwei verschiedene Zwecke (sie sind überhaupt keine Alternativen).

(bearbeitet, um Unterschiede Informationen zu erweitern)

fortdauern:

  • Fügen Sie ein neues Register in die Datenbank ein
  • Hängen Sie das Objekt an den Entitätsmanager an.

verschmelzen:

  • Suchen Sie ein angehängtes Objekt mit derselben ID und aktualisieren Sie es.
  • Wenn vorhanden, aktualisieren Sie das bereits angehängte Objekt und geben Sie es zurück.
  • Wenn es nicht existiert, fügen Sie das neue Register in die Datenbank ein.

Persistenz () Effizienz:

  • Es könnte effizienter sein, ein neues Register in eine Datenbank einzufügen als merge ().
  • Es dupliziert das ursprüngliche Objekt nicht.

persist () Semantik:

  • Es stellt sicher, dass Sie versehentlich einfügen und nicht aktualisieren.

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 etwas wie:

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 bei Verbindung mit MySQL merge () so effizient wie persist () sein kann, wenn Sie einen Aufruf von INSERT mit der Option ON DUPLICATE KEY UPDATE aufrufen, ist JPA eine Programmierung auf sehr hohem Niveau und Sie können nicht davon ausgehen, dass dies überall der Fall sein wird.


151
2018-06-11 11:04



Wenn Sie den zugewiesenen Generator verwenden, Wenn Sie Merge statt Persist verwenden, kann dies zu einer redundanten SQL-Anweisung führen, was sich auf die Leistung auswirkt.

Ebenfalls, Aufrufen von Zusammenführung für verwaltete Entitäten Dies ist auch ein Fehler, da verwaltete Entitäten automatisch von Hibernate verwaltet werden und ihr Status mit dem Datenbankeintrag synchronisiert wird schmutziger Prüfmechanismus auf den Persistenzkontext leeren.

Um zu verstehen, wie das alles funktioniert, sollten Sie zuerst wissen, dass Hibernate die Denkweise des Entwicklers von SQL-Anweisungen auf verschiebt Entitätsstatusübergänge.

Sobald eine Entität aktiv von Hibernate verwaltet wird, werden alle Änderungen automatisch an die Datenbank weitergegeben.

Hibernate überwacht derzeit angehängte Entitäten. Damit eine Entität jedoch verwaltet werden kann, muss sie sich im richtigen Entitätszustand befinden.

Zuerst müssen wir alle Entitätszustände definieren:

  • Neu (vorübergehend)

    Ein neu erstelltes Objekt, das keinem Hibernate zugeordnet wurde Session (a.k.a Persistence Context) und keiner Datenbanktabelle zugeordnet ist, wird davon ausgegangen, dass sie sich im Status Neu (Transient) befindet.

    Um dauerhaft zu bleiben, müssen wir entweder explizit die EntityManager#persist Methode oder nutzen Sie den Mechanismus der transitiven Persistenz.

  • Persistent (verwaltet)

    Eine persistente Entität wurde einer Datenbanktabellenzeile zugeordnet, und sie wird vom aktuell ausgeführten 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 beschäftigt ein Transaktionsschreibe Arbeitsstil und Änderungen werden zum letzten verantwortlichen Moment, während der aktuellen synchronisiert Session Spülzeit.

  • Freistehend

    Sobald der aktuelle Persistenzkontext geschlossen ist, werden alle zuvor verwalteten Entitäten getrennt. Nachfolgende Änderungen werden nicht mehr verfolgt, und es findet keine automatische Datenbanksynchronisierung statt.

    Um eine getrennte Entität einer aktiven Hibernate-Sitzung zuzuordnen, können Sie eine der folgenden Optionen auswählen:

    • Wiederanbringung

      Hibernate (jedoch nicht JPA 2.1) unterstützt das erneute Anhängen über die Aktualisierungsmethode Session #. Eine Hibernate-Sitzung kann nur ein Entity-Objekt für eine bestimmte Datenbankzeile verknüpfen. Dies liegt daran, dass der Persistenzkontext als In-Memory-Cache (Cache der ersten Ebene) fungiert und nur ein Wert (Entität) einem bestimmten Schlüssel (Entitätstyp und Datenbank-ID) zugeordnet ist. Eine Entität kann nur dann erneut angefügt werden, wenn kein anderes JVM-Objekt (das mit derselben Datenbankzeile übereinstimmt) bereits der aktuellen Hibernate-Sitzung zugeordnet ist.

    • Zusammenführen

    Die Zusammenführung kopiert den Status der getrennten Entität (Quelle) in eine Instanz einer verwalteten Entität (Ziel). Wenn die zusammenführende Entität in der aktuellen Sitzung keine Entsprechung hat, wird eine aus der Datenbank abgerufen. Die abgelöste Objektinstanz bleibt auch nach der Zusammenführungsoperation weiterhin getrennt.

  • Entfernt

    Obwohl JPA verlangt, dass nur verwaltete Entitäten entfernt werden dürfen, kann Hibernate auch gelöschte Entitäten löschen (jedoch nur über einen Methodenaufruf mit der Methode "Session #"). Eine entfernte Entität wird nur zum Löschen geplant, und die tatsächliche DELETE-Anweisung der Datenbank wird während der Session-Flushzeit ausgeführt.

Um die JPA-Zustandsübergänge besser zu verstehen, können Sie das folgende Diagramm visualisieren:

enter image description here

Oder wenn Sie die Hibernate-spezifische API verwenden:

enter image description here


108
2018-05-11 13:00



Das habe ich bemerkt, als ich es benutzt habe em.merge, Ich bekam ein SELECT Aussage für jeden INSERT, selbst wenn es kein Feld gab, das JPA für mich generierte - das Primärschlüsselfeld war eine UUID, die ich selbst gesetzt habe. Ich wechselte zu em.persist(myEntityObject) und habe gerade INSERT Aussagen dann.


37
2018-01-18 21:14



Die JPA-Spezifikation sagt Folgendes über persist().

Ob X ist ein losgelöstes Objekt, das EntityExistsException kann geworfen werden, wenn das bestehen bleibt   Operation wird aufgerufen, oder die EntityExistsExceptionoder ein anderes PersistenceException kann auf Flush- oder Commit-Zeit geworfen werden.

Also benutzen persist() wäre geeignet wenn das Objekt sollte nicht ein losgelöstes Objekt sein. Vielleicht möchten Sie den Code werfen lassen PersistenceException so scheitert es schnell.

Obwohl Die Spezifikation ist unklar, persist() könnte das einstellen @GeneratedValue  @Id für ein Objekt. merge() muss aber ein Objekt mit dem haben @Id bereits generiert.


27
2018-03-11 17:23



Einige weitere Details zur Zusammenführung, die Ihnen helfen werden, die Zusammenführung zu verwenden, bestehen weiterhin:

Das Zurückgeben einer anderen verwalteten Instanz als der ursprünglichen Entität ist ein kritischer Teil der Zusammenführung   verarbeiten. Wenn im Persistenzkontext bereits eine Entitätsinstanz mit dem gleichen Bezeichner existiert,   Der Anbieter überschreibt seinen Status mit dem Status der Entität, die zusammengeführt wird, aber der verwalteten Entität   Die bereits vorhandene Version muss an den Client zurückgegeben werden, damit sie verwendet werden kann. Wenn der Anbieter nicht   Aktualisieren Sie die Employee-Instanz im Persistenzkontext, so dass alle Referenzen auf diese Instanz werden   inkonsistent mit dem neuen Staat zusammengeführt werden.

Wenn merge () für eine neue Entität aufgerufen wird, verhält es sich ähnlich wie die Operation persist (). Es fügt hinzu   die Entität in den Persistenzkontext, aber anstatt die ursprüngliche Entitätsinstanz hinzuzufügen, wird eine neue Instanz erstellt   Kopieren und verwalten Sie stattdessen diese Instanz. Die Kopie, die durch die Operation merge () erstellt wird, wird beibehalten   als ob die persist () -Methode dafür aufgerufen würde.

Bei Vorhandensein von Beziehungen versucht die merge () -Operation, die verwaltete Entität zu aktualisieren   um auf verwaltete Versionen der Entitäten zu verweisen, auf die von der gelöschten Entität verwiesen wird. Wenn die Entität a   Beziehung zu einem Objekt, das keine persistente Identität hat, ist das Ergebnis der Zusammenführungsoperation   nicht definiert. Einige Provider erlauben möglicherweise, dass die verwaltete Kopie auf das nicht persistente Objekt verweist.   während andere sofort eine Ausnahme auslösen könnten. Die Operation merge () kann optional sein   in diesen Fällen kaskadiert, um das Auftreten einer Ausnahme zu verhindern. Wir werden die Kaskadierung der Zusammenführung abdecken ()   Operation später in diesem Abschnitt. Wenn eine Entität, die zusammengeführt wird, auf eine entfernte Entität zeigt, a   IllegalArgumentException-Ausnahme wird ausgelöst.

Lazy-Loading-Beziehungen sind ein Sonderfall in der Zusammenführungsoperation. Wenn ein Lazy-Loading   Beziehung wurde nicht auf eine Entität ausgelöst, bevor es losgelöst wurde, wird diese Beziehung sein   ignoriert, wenn die Entität zusammengeführt wird. Wenn die Beziehung während der Verwaltung ausgelöst und dann auf Null gesetzt wurde, während die Entität getrennt wurde, wird die Beziehung während der Zusammenführung ebenfalls in der verwalteten Version der Entität gelöscht. "

Alle obigen Informationen stammen aus "Pro JPA 2 Mastering the Java Persistence API" von Mike Keith und Merrick Schnicariol. Kapitel 6. Abtrennung und Zusammenführung von Abschnitten. Dieses Buch ist eigentlich ein zweites Buch, das den Autoren von JPA gewidmet ist. Dieses neue Buch hat viele neue Informationen als früher. Ich empfehle wirklich, dieses Buch für diejenigen zu lesen, die sich ernsthaft mit JPA beschäftigen werden. Es tut mir leid, dass ich meine erste Antwort anonym gepostet habe.


16
2017-10-05 13:00



Es gibt einige Unterschiede zwischen merge und persist (Ich werde die schon hier geposteten wieder aufzählen):

D1. merge macht die übergebene Entität nicht verwaltet, sondern gibt eine andere Instanz zurück, die verwaltet wird. persist Auf der anderen Seite wird die übergebene Entität verwaltet:

//MERGE: passedEntity remains unmanaged, but newEntity will be managed
Entity newEntity = em.merge(passedEntity);

//PERSIST: passedEntity will be managed after this
em.persist(passedEntity);

D2. Wenn Sie eine Entität entfernen und dann entscheiden, die Entität beizubehalten, können Sie dies nur mit persist () tun, weil merge wirf einen IllegalArgumentException.

D3. Wenn Sie sich entschieden haben, Ihre IDs manuell anzupassen (z. B. mithilfe von UUIDs), dann a merge  Die Operation wird anschließend ausgelöst SELECT Abfragen, um nach vorhandenen Entitäten mit dieser ID zu suchen, während persist Möglicherweise brauchen diese Abfragen nicht.

D4. Es gibt Fälle, in denen Sie einfach nicht dem Code vertrauen, der Ihren Code aufruft, und um sicherzustellen, dass keine Daten aktualisiert, sondern eingefügt werden, müssen Sie verwenden persist.


15
2017-12-02 14:13