What is the difference between persist() and merge() in JPA and Hibernate?

В чем разница между persist() и merge() в Hibernate?

persist() может создать запрос UPDATE & INSERT, например:

SessionFactory sef = cfg.buildSessionFactory();
Session session = sef.openSession();
A a=new A();
session.persist(a);
a.setName("Mario");
session.flush();

в этом случае запрос будет сгенерирован так:

Hibernate: insert into A (NAME, ID) values (?, ?)
Hibernate: update A set NAME=? where ID=?

так persist() Метод может генерировать вставку и обновление.

Теперь с merge():

SessionFactory sef = cfg.buildSessionFactory();
Session session = sef.openSession();
Singer singer = new Singer();
singer.setName("Luciano Pavarotti");
session.merge(singer);
session.flush();

Вот что я вижу в базе данных:

SINGER_ID   SINGER_NAME
1           Ricky Martin
2           Madonna
3           Elvis Presley
4           Luciano Pavarotti

Теперь обновите запись, используя merge()

SessionFactory sef = cfg.buildSessionFactory();
Session session = sef.openSession();
Singer singer = new Singer();
singer.setId(2);
singer.setName("Luciano Pavarotti");
session.merge(singer);
session.flush();

Вот что я вижу в базе данных:

SINGER_ID   SINGER_NAME
1           Ricky Martin
2           Luciano Pavarotti
3           Elvis Presley

3 ответа

Решение

Спецификация JPA содержит очень точное описание семантики этих операций, лучше, чем в javadoc:

Семантика сохраняемой операции, применяемой к сущности X, следующая:

  • Если X новый объект, он становится управляемым. Объект X будет введен в базу данных во время или до принятия транзакции или в результате операции сброса.

  • Если X - это уже существующий управляемый объект, он игнорируется операцией persist. Однако операция persist каскадно относится к объектам, на которые ссылается X, если отношения между X и этими другими объектами аннотируются cascade=PERSIST или же cascade=ALL значение элемента аннотации или указано с помощью эквивалентного элемента дескриптора XML.

  • Если X является удаленным объектом, он становится управляемым.

  • Если X является отдельным объектом, EntityExistsException может быть сгенерировано, когда вызывается постоянная операция, или EntityExistsException или другой PersistenceException может быть брошено на флеш или совершить время.

  • Для всех объектов Y, на которые ссылается отношение из X, если отношение к Y было аннотировано значением элемента каскада cascade=PERSIST или же cascade=ALL, постоянная операция применяется к Y.


Семантика операции слияния, примененной к сущности X, следующая:

  • Если X является отсоединенным объектом, состояние X копируется в ранее существующий экземпляр управляемого объекта X'с таким же идентификатором или создается новая управляемая копия X' из X.

  • Если X является новым экземпляром объекта, создается новый экземпляр X'управляемого объекта, и состояние X копируется в новый экземпляр X' управляемого объекта.

  • Если X является удаленным экземпляром объекта, IllegalArgumentException будет сброшен операцией слияния (или фиксация транзакции завершится неудачно).

  • Если X является управляемым объектом, он игнорируется операцией слияния, однако операция слияния каскадно объединяется с объектами, на которые ссылаются отношения из X, если эти отношения были аннотированы значением элемента каскада cascade=MERGE или же cascade=ALL аннотаций.

  • Для всех объектов Y, на которые ссылаются отношения из X, имеющие значение элемента каскада cascade=MERGE или же cascade=ALLY объединяется рекурсивно как Y'. Для всех таких Y, на которые ссылается X, X'устанавливается на ссылку Y'. (Обратите внимание, что если X управляется, то X является тем же объектом, что и X'.)

  • Если X является объектом, объединенным с X', со ссылкой на другой объект Y, где cascade=MERGE или же cascade=ALL не указывается, то навигация той же ассоциации из X'дает ссылку на управляемый объект Y' с той же постоянной идентичностью, что и Y.

Это исходит от JPA. Очень простым способом:

persist (entity) должен использоваться с абсолютно новыми сущностями, чтобы добавить их в БД (если сущность уже существует в БД, будет выброшено исключение EntityExistsException).

Слияние (сущность) должно использоваться, чтобы вернуть сущность обратно в контекст постоянства, если сущность была отсоединена и была изменена.

Persist следует вызывать только для новых объектов, а объединение предназначено для повторного присоединения отдельных объектов.

Если вы используете назначенный генератор, использование слияния вместо постоянного может привести к созданию избыточного оператора SQL, что повлияет на производительность.

Кроме того, вызов слияния для управляемых объектов также является ошибкой, поскольку Hibernate автоматически управляет управляемыми объектами, а их состояние синхронизируется с записью базы данных с помощью механизма грязной проверки после сброса контекста персистентности.

Самое важное различие заключается в следующем: в случае метода постоянства, если объект, которым необходимо управлять в контексте постоянства, уже существует в контексте постоянства, новый объект игнорируется. (НИЧЕГО не произошло) Но в случае метода слияния сущность, которой уже управляют в контексте постоянства, будет заменена новой сущностью (обновленной), а копия этой обновленной сущности вернется обратно. (отныне любые изменения должны быть сделаны в этой возвращенной сущности, если вы хотите отразить свои изменения в контексте постоянства)

Другие вопросы по тегам