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=ALL
Y объединяется рекурсивно как 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 автоматически управляет управляемыми объектами, а их состояние синхронизируется с записью базы данных с помощью механизма грязной проверки после сброса контекста персистентности.
Самое важное различие заключается в следующем: в случае метода постоянства, если объект, которым необходимо управлять в контексте постоянства, уже существует в контексте постоянства, новый объект игнорируется. (НИЧЕГО не произошло) Но в случае метода слияния сущность, которой уже управляют в контексте постоянства, будет заменена новой сущностью (обновленной), а копия этой обновленной сущности вернется обратно. (отныне любые изменения должны быть сделаны в этой возвращенной сущности, если вы хотите отразить свои изменения в контексте постоянства)