Frage

Hibernate hat eine Handvoll von Methoden, die eine oder andere Weise, Ihre Aufgabe übernimmt und legt sie in die Datenbank. Was sind die Unterschiede zwischen ihnen, wenn zu verwenden, die, und warum ist nicht da nur eine intelligente Methode, die weiß, wann was zu verwenden?

Die Methoden, die ich bisher identifiziert haben, sind:

  • save()
  • update()
  • saveOrUpdate()
  • saveOrUpdateCopy()
  • merge()
  • persist()
War es hilfreich?

Lösung

Hier ist mein Verständnis der Methoden. Hauptsächlich werden diese auf der API obwohl, wie ich don ‚t all diese in der Praxis verwendet werden.

saveOrUpdate Anrufe entweder speichern oder zu aktualisieren, je nach einigen Prüfungen. Z.B. wenn keine Kennung vorhanden ist, speichern genannt wird. Ansonsten Update aufgerufen wird.

Speichern Weiterhin besteht eine Einheit. Wird eine Kennung zuweisen, wenn man nicht existiert. Wenn man tut, ist es im Wesentlichen ein Update zu tun. Gibt das generierte ID des Unternehmens steht.

Update Versuche, die Einheit unter Verwendung einer vorhandenen Kennung bestehen bleiben. Wenn keine Kennung vorhanden ist, glaube ich, eine Ausnahme ausgelöst wird.

saveOrUpdateCopy Dies ist veraltet und nicht mehr verwendet werden soll. Stattdessen gibt es ...

fusionieren Nun ist dies, wo mein Wissen zu stocken beginnt. Wichtig dabei ist der Unterschied zwischen transienter, freistehend und persistent Einheiten. Für weitere Informationen über die Objektzustände, nehmen Sie einen Blick hier . Mit speichern und zu aktualisieren, es zu tun haben Sie mit persistenten Objekten. Sie sind an einer Session verknüpft, so Hibernate weiß, was sich geändert hat. Aber wenn man ein transientes Objekt hat, gibt es keine Sitzung beteiligt. In diesen Fällen müssen Sie für Updates fusionieren verwenden und für das Speichern bestehen bleiben.

bestehen Wie oben erwähnt, wird diese auf transiente Objekte verwendet. Es ist nicht die erzeugte ID zurück.

Andere Tipps

╔══════════════╦═══════════════════════════════╦════════════════════════════════╗
║    METHOD    ║            TRANSIENT          ║            DETACHED            ║
╠══════════════╬═══════════════════════════════╬════════════════════════════════╣
║              ║       sets id if doesn't      ║   sets new id even if object   ║
║    save()    ║     exist, persists to db,    ║    already has it, persists    ║
║              ║    returns attached object    ║ to DB, returns attached object ║
╠══════════════╬═══════════════════════════════╬════════════════════════════════╣
║              ║       sets id on object       ║             throws             ║
║   persist()  ║     persists object to DB     ║       PersistenceException     ║
║              ║                               ║                                ║
╠══════════════╬═══════════════════════════════╬════════════════════════════════╣
║              ║                               ║                                ║
║   update()   ║           Exception           ║     persists and reattaches    ║
║              ║                               ║                                ║
╠══════════════╬═══════════════════════════════╬════════════════════════════════╣
║              ║  copy the state of object in  ║    copy the state of obj in    ║
║    merge()   ║     DB, doesn't attach it,    ║      DB, doesn't attach it,    ║
║              ║    returns attached object    ║     returns attached object    ║
╠══════════════╬═══════════════════════════════╬════════════════════════════════╣
║              ║                               ║                                ║
║saveOrUpdate()║           as save()           ║            as update()         ║
║              ║                               ║                                ║
╚══════════════╩═══════════════════════════════╩════════════════════════════════╝
  • Sehen Sie die Hibernate Forum eine Erklärung für die feinen Unterschiede zwischen bestehen bleiben und speichern. Es sieht aus wie die Differenz der Zeit die INSERT-Anweisung wird schließlich ausgeführt. Da Speichern Sie die Kennung zurückgibt, hat die INSERT-Anweisung sofort unabhängig von der Transaktion des Staates ausgeführt werden (die in der Regel eine schlechte Sache ist). Persist wird keine Anweisungen ausführen außerhalb der aktuell nur zuweisen der Kennung laufenden Transaktion. Speichern / Persist beide arbeiten auf transiente Instanzen , dh Instanzen, die keine Kennung haben zugewiesen noch und sind als solche in der DB nicht gespeichert.

  • Aktualisieren und Zusammenführen arbeiten beide auf freistehende Instanzen , dh Instanzen, die einen entsprechenden Eintrag in der DB haben, die jedoch zur Zeit nicht eine Session an (von oder verwaltet werden). Der Unterschied zwischen ihnen ist, was zum Beispiel passiert, die an die Funktion übergeben wird. Update versucht die Instanz wieder zu befestigen, das heißt, dass es an der Sitzung gebunden jetzt sonst eine Ausnahme ausgelöst wird, keine andere Instanz der persistenten Einheit sein kann. fusioniert , jedoch nur kopiert alle Werte zu einer persistenten Instanz in der Session (die geladen wird, wenn es nicht zur Zeit geladen ist). Das Eingangsobjekt wird nicht verändert. So fusionieren ist allgemeiner als Update , kann aber mehr Ressourcen verwenden.

Dieser Link erklärt in guter Weise:

http://www.stevideter.com/2008/12/ 07 / saveorupdate-versus-Merge-in-Hibernate /

Wir haben all die Probleme, die wir nur selten genug begegnen, dass, wenn wir sie wieder sehen, wir wissen, dass wir dieses Problem gelöst haben, aber nicht mehr, wie.

Die NonUniqueObjectException geworfen, wenn Session.saveOrUpdate () in Hibernate ist eine von mir. Ich werde neue Funktionalität einer komplexen Anwendung hinzufügen. Alle meine Unit-Tests funktionieren. Dann in die Benutzeroberfläche testen, versuchen, ein Objekt zu speichern, ich anfangen, eine Ausnahme mit der Meldung „ein anderen Objekt mit dem gleichen Wert Kennung wurde bereits mit der Sitzung verknüpft ist.“ Hier einig Beispiel-Code von Java Persistence mit Hibernate.

            Session session = sessionFactory1.openSession();
            Transaction tx = session.beginTransaction();
            Item item = (Item) session.get(Item.class, new Long(1234));
            tx.commit();
            session.close(); // end of first session, item is detached

            item.getId(); // The database identity is "1234"
            item.setDescription("my new description");
            Session session2 = sessionFactory.openSession();
            Transaction tx2 = session2.beginTransaction();
            Item item2 = (Item) session2.get(Item.class, new Long(1234));
            session2.update(item); // Throws NonUniqueObjectException
            tx2.commit();
            session2.close();

die Ursache dieser Ausnahme zu verstehen, ist es wichtig, frei stehende Objekte zu verstehen und was passiert, wenn man saveOrUpdate () aufrufen (oder nur update ()) auf einem frei stehenden Objekt.

Wenn wir schließen eine individuelle Hibernate Session, die persistenten Objekte, mit denen wir losgelöst arbeiten. Dies bedeutet, dass die Daten noch im Speicher der Anwendung, aber Hibernate ist nicht mehr verantwortlich für Änderungen an die Objekte zu verfolgen.

Wenn wir dann unser freistehendes Objekt ändern und aktualisieren wollen, müssen wir das Objekt wieder an. Während dieser Wiederanheftung Prozess wird Hibernate überprüfen, um zu sehen, ob es noch andere Kopien desselben Objekts sind. Wenn es welche findet, hat es uns zu sagen, es weiß nicht, was die „echte“ Kopie ist nicht mehr. Vielleicht sind andere Änderungen wurden an diesen anderen Kopien gemacht, dass wir gerettet werden erwarten, aber Hibernate weiß nicht, über sie, weil es nicht war sie zu der Zeit zu verwalten.

Anstatt möglicherweise fehlerhafte Daten zu speichern, Hibernate erzählt uns über das Problem über das NonUniqueObjectException.

Also, was sollen wir tun? In dem Ruhezustand 3, haben wir fusionieren () (in dem Ruhezustand 2, verwendet saveOrUpdateCopy ()). Diese Methode wird Hibernate zwingen, alle Änderungen von anderen abgelöst Instanzen auf die Instanz zu kopieren, die Sie speichern möchten, und damit verschmilzt alle Änderungen im Speicher vor dem Speichern.

        Session session = sessionFactory1.openSession();
        Transaction tx = session.beginTransaction();
        Item item = (Item) session.get(Item.class, new Long(1234));
        tx.commit();
        session.close(); // end of first session, item is detached

        item.getId(); // The database identity is "1234"
        item.setDescription("my new description");
        Session session2 = sessionFactory.openSession();
        Transaction tx2 = session2.beginTransaction();
        Item item2 = (Item) session2.get(Item.class, new Long(1234));
        Item item3 = session2.merge(item); // Success!
        tx2.commit();
        session2.close();

Es ist wichtig, dass merge gibt einen Verweis auf die neu aktualisierte Version der Instanz zu beachten. Es ist nicht auf die Session reattaching Artikel. Wenn Sie zum Beispiel Gleichheit testen (Artikel == item3), finden Sie es in diesem Fall falsch zurückgibt. Sie werden wahrscheinlich mit item3 von diesem Punkt an arbeiten.

Es ist auch wichtig zu beachten, dass die Java Persistence API (JPA) hat kein Konzept abgelöst und wieder angebracht Objekte und verwendet EntityManager.persist () und EntityManager.merge ().

Ich habe im Allgemeinen festgestellt, dass bei der Verwendung von Hibernate, saveOrUpdate () für meine Bedürfnisse in der Regel ausreichend ist. Ich muss in der Regel nur Druck verwenden, wenn ich Objekte, die Verweise auf Objekte des gleichen Typs haben kann. Zuletzt war die Ursache für die Ausnahme im Code validieren, dass der Verweis nicht rekursiv war. Ich war das gleiche Objekt in meine Session im Rahmen der Validierung Laden, der den Fehler verursacht.

Wo haben Sie dieses Problem gestoßen? Haben fusionieren für Sie zur Arbeit oder haben müssen Sie eine andere Lösung? Bevorzugen Sie immer Druck verwenden, oder lieber nur verwenden, wie für bestimmte Fälle benötigen

Eigentlich ist der Unterschied zwischen Hibernate save() und persist() Methoden ist, hängt von Generator Klasse, die wir verwenden.

Wenn unser Generator Klasse zugeordnet ist, dann gibt es keinen Unterschied zwischen save() und persist() Methoden. Da Generator ‚zugeordnet‘ bedeutet, als Programmierer müssen wir den Primärschlüsselwert geben, direkt in der Datenbank speichern [Hoffnung kennen Sie diese Generatoren Konzept] Im Falle einer anderen als Generator-Klasse zugeordnet, nehme an, wenn unser Generator Klassenname bedeutet Increment es Hibernate selbst wird der Primärschlüssel-ID-Wert in die Datenbank richtig [außer zugewiesen Generator zuweisen, wird nur der Primärschlüssel-ID-Wert nehmen verwendet wintern kümmern erinnern in diesem Fall], so dass, wenn wir save() oder persist() Methode aufrufen, dann wird es den Datensatz in die Datenbank einfügen normalerweise Aber hören Sache ist, save() Methode, dass die Primärschlüssel-ID-Wert zurückgeben kann, die durch Hibernate erzeugt wird, und wir können es durch

siehe
long s = session.save(k);

In diesem gleichen Fall persist() wird nie wieder einen Wert geben, um die Kunden.

Ich fand ein gutes Beispiel die Unterschiede zwischen alle zeigen Methoden winter sparen:

http: // www. journaldev.com/3481/hibernate-session-merge-vs-update-save-saveorupdate-persist-example

Kurz gesagt, nach dem obigen Link:

save ()

  • Wir können diese Methode außerhalb einer Transaktion aufrufen. Wenn wir dies ohne Transaktion verwenden, und wir haben Kaskadierung zwischen Entitäten, dann wird nur die primäre Entität wird gespeichert, wenn wir die Sitzung spülen.
  • Also, wenn es andere Objekte aus dem primären Objekt abgebildet sind, die zum Zeitpunkt der Begehung Transaktion gespeichert wird oder wenn wir die Sitzung spülen.

bestehen ()

  • Sein ähnliches mit save () in der Transaktion, so ist es sicher und kümmert sich um eine beliebige Objekte kaskadiert werden.

saveOrUpdate ()

  • Mit oder ohne die Transaktion verwendet werden, und wie save (), wenn sie ohne die Transaktion verwendet, kartiert Einheiten werden nicht gespeichert un werden; ess wir die Sitzung spülen

  • .
  • Ergebnisse in Insert oder Update-Abfragen auf der Grundlage der zur Verfügung gestellten Daten. Wenn die Daten in der Datenbank vorhanden sind, Update-Abfrage ausgeführt.

update ()

  • sollte Hibernate Update verwendet werden, wo wir wissen, dass wir das Unternehmen Informationen nur aktualisieren. Dieser Vorgang fügt das Unternehmen Objekt persistent Kontext und weitere Änderungen verfolgt und gespeichert, wenn Transaktion festgeschrieben wird.
  • Daher sogar Update nach dem Aufruf, wenn wir alle Werte in der Einheit festgelegt, werden sie aktualisiert, wenn Transaktion festgeschrieben.

fusionieren ()

  • Hibernate merge kann verwendet werden, bestehende Werte zu aktualisieren, aber diese Methode eine Kopie von dem übergebenen Entitätsobjekt erstellen und es zurück. Das zurückgegebene Objekt Teil persistenten Kontext ist und für alle Änderungen verfolgt, übergebene Objekt wird nicht verfolgt. Dies ist der Hauptunterschied mit merge () von allen anderen Methoden.

Auch für praktische Beispiele für all diese bitte auf den Link verweise ich oben erwähnt, zeigt es Beispiele für all diese verschiedenen Methoden.

Beachten Sie, dass, wenn Sie ein Update rufen auf einem freistehendes Objekt, wird es immer ein Update in der Datenbank durchgeführt werden, ob Sie das Objekt veränderten oder nicht. Wenn es nicht das, was Sie wollen, sollten Sie Session.lock () mit LockMode.None verwenden.

Sie sollten Update nur aufrufen, wenn das Objekt außerhalb des Bereichs der aktuellen Sitzung geändert wurde (im gelösten Zustand).

As I explained in this article, you should prefer the JPA methods most of the time, and the update for batch processing tasks.

A JPA or Hibernate entity can be in one of the following four states:

  • Transient (New)
  • Managed (Persistent)
  • Detached
  • Removed (Deleted)

The transition from one state to the other is done via the EntityManager or Session methods.

For instance, the JPA EntityManager provides the following entity state transition methods.

enter image description here

The Hibernate Session implements all the JPA EntityManager methods and provides some additional entity state transition methods like save, saveOrUpdate and update.

enter image description here

Persist

To change the state of an entity from Transient (New) to Managed (Persisted), we can use the persist method offered by the JPA EntityManager which is also inherited by the Hibernate Session.

The persist method triggers a PersistEvent which is handled by the DefaultPersistEventListener Hibernate event listener.

Therefore, when executing the following test case:

doInJPA(entityManager -> {
    Book book = new Book()
    .setIsbn("978-9730228236")
    .setTitle("High-Performance Java Persistence")
    .setAuthor("Vlad Mihalcea");

    entityManager.persist(book);

    LOGGER.info(
        "Persisting the Book entity with the id: {}", 
        book.getId()
    );
});

Hibernate generates the following SQL statements:

CALL NEXT VALUE FOR hibernate_sequence

-- Persisting the Book entity with the id: 1

INSERT INTO book (
    author, 
    isbn, 
    title, 
    id
) 
VALUES (
    'Vlad Mihalcea', 
    '978-9730228236', 
    'High-Performance Java Persistence', 
    1
)

Notice that the id is assigned prior to attaching the Book entity to the current Persistence Context. This is needed because the managed entities are stored in a Map structure where the key is formed by the entity type and its identifier and the value is the entity reference. This is the reason why the JPA EntityManager and the Hibernate Session are known as the First-Level Cache.

When calling persist, the entity is only attached to the currently running Persistence Context, and the INSERT can be postponed until the flush is called.

The only exception is the IDENTITY generator which triggers the INSERT right away since that's the only way it can get the entity identifier. For this reason, Hibernate cannot batch inserts for entities using the IDENTITY generator. For more details about this topic, check out this article.

Save

The Hibernate-specific save method predates JPA and it's been available since the beginning of the Hibernate project.

The save method triggers a SaveOrUpdateEvent which is handled by the DefaultSaveOrUpdateEventListener Hibernate event listener. Therefore, the save method is equivalent to the update and saveOrUpdate methods.

To see how the save method works, consider the following test case:

doInJPA(entityManager -> {
    Book book = new Book()
    .setIsbn("978-9730228236")
    .setTitle("High-Performance Java Persistence")
    .setAuthor("Vlad Mihalcea");

    Session session = entityManager.unwrap(Session.class);

    Long id = (Long) session.save(book);

    LOGGER.info(
        "Saving the Book entity with the id: {}", 
        id
    );
});

When running the test case above, Hibernate generates the following SQL statements:

CALL NEXT VALUE FOR hibernate_sequence

-- Saving the Book entity with the id: 1

INSERT INTO book (
    author, 
    isbn, 
    title, 
    id
) 
VALUES (
    'Vlad Mihalcea', 
    '978-9730228236', 
    'High-Performance Java Persistence', 
    1
)

As you can see, the outcome is identical to the persist method call. However, unlike persist, the save method returns the entity identifier.

For more details, check out this article.

Update

The Hibernate-specific update method is meant to bypass the dirty checking mechanism and force an entity update at the flush time.

The update method triggers a SaveOrUpdateEvent which is handled by the DefaultSaveOrUpdateEventListener Hibernate event listener. Therefore, the update method is equivalent to the save and saveOrUpdate methods.

To see how the update method works consider the following example which persists a Book entity in one transaction, then it modifies it while the entity is in the detached state, and it forces the SQL UPDATE using the update method call.

Book _book = doInJPA(entityManager -> {
    Book book = new Book()
    .setIsbn("978-9730228236")
    .setTitle("High-Performance Java Persistence")
    .setAuthor("Vlad Mihalcea");

    entityManager.persist(book);

    return book;
});

LOGGER.info("Modifying the Book entity");

_book.setTitle(
    "High-Performance Java Persistence, 2nd edition"
);

doInJPA(entityManager -> {
    Session session = entityManager.unwrap(Session.class);

    session.update(_book);

    LOGGER.info("Updating the Book entity");
});

When executing the test case above, Hibernate generates the following SQL statements:

CALL NEXT VALUE FOR hibernate_sequence

INSERT INTO book (
    author, 
    isbn, 
    title, 
    id
) 
VALUES (
    'Vlad Mihalcea', 
    '978-9730228236', 
    'High-Performance Java Persistence', 
    1
)

-- Modifying the Book entity
-- Updating the Book entity

UPDATE 
    book 
SET 
    author = 'Vlad Mihalcea', 
    isbn = '978-9730228236', 
    title = 'High-Performance Java Persistence, 2nd edition'
WHERE 
    id = 1

Notice that the UPDATE is executed during the Persistence Context flush, right before commit, and that's why the Updating the Book entity message is logged first.

Using @SelectBeforeUpdate to avoid unnecessary updates

Now, the UPDATE is always going to be executed even if the entity was not changed while in the detached state. To prevent this, you can use the @SelectBeforeUpdate Hibernate annotation which will trigger a SELECT statement that fetched loaded state which is then used by the dirty checking mechanism.

So, if we annotate the Book entity with the @SelectBeforeUpdate annotation:

@Entity(name = "Book")
@Table(name = "book")
@SelectBeforeUpdate
public class Book {

    //Code omitted for brevity
}

And execute the following test case:

Book _book = doInJPA(entityManager -> {
    Book book = new Book()
    .setIsbn("978-9730228236")
    .setTitle("High-Performance Java Persistence")
    .setAuthor("Vlad Mihalcea");

    entityManager.persist(book);

    return book;
});

doInJPA(entityManager -> {
    Session session = entityManager.unwrap(Session.class);

    session.update(_book);
});

Hibernate executes the following SQL statements:

INSERT INTO book (
    author, 
    isbn, 
    title, 
    id
) 
VALUES (
    'Vlad Mihalcea', 
    '978-9730228236', 
    'High-Performance Java Persistence', 
    1
)

SELECT 
    b.id,
    b.author AS author2_0_,
    b.isbn AS isbn3_0_,
    b.title AS title4_0_
FROM 
    book b
WHERE 
    b.id = 1

Notice that, this time, there is no UPDATE executed since the Hibernate dirty checking mechanism has detected that the entity was not modified.

SaveOrUpdate

The Hibernate-specific saveOrUpdate method is just an alias for save and update.

The saveOrUpdate method triggers a SaveOrUpdateEvent which is handled by the DefaultSaveOrUpdateEventListener Hibernate event listener. Therefore, the update method is equivalent to the save and saveOrUpdate methods.

Now, you can use saveOrUpdate when you want to persist an entity or to force an UPDATE as illustrated by the following example.

Book _book = doInJPA(entityManager -> {
    Book book = new Book()
    .setIsbn("978-9730228236")
    .setTitle("High-Performance Java Persistence")
    .setAuthor("Vlad Mihalcea");

    Session session = entityManager.unwrap(Session.class);
    session.saveOrUpdate(book);

    return book;
});

_book.setTitle("High-Performance Java Persistence, 2nd edition");

doInJPA(entityManager -> {
    Session session = entityManager.unwrap(Session.class);
    session.saveOrUpdate(_book);
});

Beware of the NonUniqueObjectException

One problem that can occur with save, update, and saveOrUpdate is if the Persistence Context already contains an entity reference with the same id and of the same type as in the following example:

Book _book = doInJPA(entityManager -> {
    Book book = new Book()
    .setIsbn("978-9730228236")
    .setTitle("High-Performance Java Persistence")
    .setAuthor("Vlad Mihalcea");

    Session session = entityManager.unwrap(Session.class);
    session.saveOrUpdate(book);

    return book;
});

_book.setTitle(
    "High-Performance Java Persistence, 2nd edition"
);

try {
    doInJPA(entityManager -> {
        Book book = entityManager.find(
            Book.class, 
            _book.getId()
        );

        Session session = entityManager.unwrap(Session.class);
        session.saveOrUpdate(_book);
    });
} catch (NonUniqueObjectException e) {
    LOGGER.error(
        "The Persistence Context cannot hold " +
        "two representations of the same entity", 
        e
    );
}

Now, when executing the test case above, Hibernate is going to throw a NonUniqueObjectException because the second EntityManager already contains a Book entity with the same identifier as the one we pass to update, and the Persistence Context cannot hold two representations of the same entity.

org.hibernate.NonUniqueObjectException: 
    A different object with the same identifier value was already associated with the session : [com.vladmihalcea.book.hpjp.hibernate.pc.Book#1]
    at org.hibernate.engine.internal.StatefulPersistenceContext.checkUniqueness(StatefulPersistenceContext.java:651)
    at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.performUpdate(DefaultSaveOrUpdateEventListener.java:284)
    at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.entityIsDetached(DefaultSaveOrUpdateEventListener.java:227)
    at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.performSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:92)
    at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:73)
    at org.hibernate.internal.SessionImpl.fireSaveOrUpdate(SessionImpl.java:682)
    at org.hibernate.internal.SessionImpl.saveOrUpdate(SessionImpl.java:674)

Merge

To avoid the NonUniqueObjectException, you need to use the merge method offered by the JPA EntityManager and inherited by the Hibernate Session as well.

As explained in this article, the merge fetches a new entity snapshot from the database if there is no entity reference found in the Persistence Context, and it copies the state of the detached entity passed to the merge method.

The merge method triggers a MergeEvent which is handled by the DefaultMergeEventListener Hibernate event listener.

To see how the merge method works consider the following example which persists a Book entity in one transaction, then it modifies it while the entity is in the detached state, and pass the detached entity to merge in a subsequence Persistence Context.

Book _book = doInJPA(entityManager -> {
    Book book = new Book()
    .setIsbn("978-9730228236")
    .setTitle("High-Performance Java Persistence")
    .setAuthor("Vlad Mihalcea");

    entityManager.persist(book);

    return book;
});

LOGGER.info("Modifying the Book entity");

_book.setTitle(
    "High-Performance Java Persistence, 2nd edition"
);

doInJPA(entityManager -> {
    Book book = entityManager.merge(_book);

    LOGGER.info("Merging the Book entity");

    assertFalse(book == _book);
});

When running the test case above, Hibernate executed the following SQL statements:

INSERT INTO book (
    author, 
    isbn, 
    title, 
    id
) 
VALUES (
    'Vlad Mihalcea', 
    '978-9730228236', 
    'High-Performance Java Persistence', 
    1
)

-- Modifying the Book entity

SELECT 
    b.id,
    b.author AS author2_0_,
    b.isbn AS isbn3_0_,
    b.title AS title4_0_
FROM 
    book b
WHERE 
    b.id = 1

-- Merging the Book entity

UPDATE 
    book 
SET 
    author = 'Vlad Mihalcea', 
    isbn = '978-9730228236', 
    title = 'High-Performance Java Persistence, 2nd edition'
WHERE 
    id = 1

Notice that the entity reference returned by merge is different than the detached one we passed to the merge method.

Now, although you should prefer using JPA merge when copying the detached entity state, the extra SELECT can be problematic when executing a batch processing task.

For this reason, you should prefer using update when you are sure that there is no entity reference already attached to the currently running Persistence Context and that the detached entity has been modified.

For more details about this topic, check out this article.

Conclusion

To persist an entity, you should use the JPA persist method. To copy the detached entity state, merge should be preferred. The update method is useful for batch processing tasks only. The save and saveOrUpdate are just aliases to update and you should not probably use them at all.

Some developers call save even when the entity is already managed, but this is a mistake and triggers a redundant event since, for managed entities, the UPDATE is automatically handled at the Persistence context flush time.

For more details, check out this article.

None of the following answers are right. All these methods just seem to be alike, but in practice do absolutely different things. It is hard to give short comments. Better to give a link to full documentation about these methods: http://docs.jboss.org/hibernate/core/3.6/reference/en-US/html/objectstate.html

None of the answers above are complete. Although Leo Theobald answer looks nearest answer.

The basic point is how hibernate is dealing with states of entities and how it handles them when there is a state change. Everything must be seen with respect to flushes and commits as well, which everyone seems to have ignored completely.

NEVER USE THE SAVE METHOD of HIBERNATE. FORGET THAT IT EVEN EXISTS IN HIBERNATE!

Persist

As everyone explained, Persist basically transitions an entity from "Transient" state to "Managed" State. At this point, a slush or a commit can create an insert statement. But the entity will still remains in "Managed" state. That doesn't change with flush.

At this point, if you "Persist" again there will be no change. And there wont be any more saves if we try to persist a persisted entity.

The fun begins when we try to evict the entity.

An evict is a special function of Hibernate which will transition the entity from "Managed" to "Detached". We cannot call a persist on a detached entity. If we do that, then Hibernate raises an exception and entire transaction gets rolled back on commit.

Merge vs Update

These are 2 interesting functions doing different stuff when dealt in different ways. Both of them are trying to transition the entity from "Detached" state to "Managed" state. But doing it differently.

Understand a fact that Detached means kind of an "offline" state. and managed means "Online" state.

Observe the code below:

Session ses1 = sessionFactory.openSession();

    Transaction tx1 = ses1.beginTransaction();

    HibEntity entity = getHibEntity();

    ses1.persist(entity);
    ses1.evict(entity);

    ses1.merge(entity);

    ses1.delete(entity);

    tx1.commit();

When you do this? What do you think will happen? If you said this will raise exception, then you are correct. This will raise exception because, merge has worked on entity object, which is detached state. But it doesn't alter the state of object.

Behind the scene, merge will raise a select query and basically returns a copy of entity which is in attached state. Observe the code below:

Session ses1 = sessionFactory.openSession();

    Transaction tx1 = ses1.beginTransaction();
    HibEntity entity = getHibEntity();

    ses1.persist(entity);
    ses1.evict(entity);

    HibEntity copied = (HibEntity)ses1.merge(entity);
    ses1.delete(copied);

    tx1.commit();

The above sample works because merge has brought a new entity into the context which is in persisted state.

When applied with Update the same works fine because update doesn't actually bring a copy of entity like merge.

Session ses1 = sessionFactory.openSession();

    Transaction tx1 = ses1.beginTransaction();

    HibEntity entity = getHibEntity();

    ses1.persist(entity);
    ses1.evict(entity);

    ses1.update(entity);

    ses1.delete(entity);

    tx1.commit();

At the same time in debug trace we can see that Update hasn't raised SQL query of select like merge.

delete

In the above example I used delete without talking about delete. Delete will basically transition the entity from managed state to "removed" state. And when flushed or commited will issue a delete command to store.

However it is possible to bring the entity back to "managed" state from "removed" state using the persist method.

Hope the above explanation clarified any doubts.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top