Вот мое понимание методов. В основном они основаны на API хотя я не использую все это на практике.
saveOrUpdate
Вызовы сохранить или обновить в зависимости от некоторых проверок. Например, если идентификатора не существует, вызывается save. В противном случае обновление называется.
Сохранить
Сохраняет сущность. Назначит идентификатор, если он не существует. Если это так, то, по сути, это обновление. Возвращает сгенерированный идентификатор объекта.
обновить
Попытки сохранить сущность, используя существующий идентификатор. Если идентификатора не существует, я полагаю, что выдается исключение.
saveOrUpdateCopy
Это устарело и больше не должно использоваться. Вместо этого есть ...
Слияние
Теперь, когда мои знания начинают давать сбои. Здесь важна разница между временными, обособленными и постоянными объектами. Для получения дополнительной информации о состояниях объекта, посмотрите здесь . С помощью сохранения и обновления вы имеете дело с постоянными объектами. Они связаны с сеансом, поэтому Hibernate знает, что изменилось. Но когда у вас есть временный объект, сеанс не включается. В этих случаях вам нужно использовать слияние для обновлений и сохранять для сохранения.
persist
Как упоминалось выше, это используется для временных объектов. Он не возвращает сгенерированный идентификатор.
источник
update
переходный объект в порядке, я не получил исключение.Смотрите Hibernate Forum для объяснения тонких различий между сохранением и сохранением. Похоже, разница в том, когда в конечном итоге выполняется оператор INSERT. Так как save возвращает идентификатор, оператор INSERT должен выполняться немедленно, независимо от состояния транзакции (что, как правило, плохо). Persist не будет выполнять какие-либо операторы вне текущей выполняемой транзакции только для назначения идентификатора. Save / Persist работают как с временными экземплярами , то есть с экземплярами, которым еще не назначен идентификатор, и как таковые они не сохраняются в БД.
Update и Merge работают с отдельными экземплярами , то есть с экземплярами, которые имеют соответствующую запись в БД, но которые в настоящее время не присоединены (или не управляются) к сеансу. Разница между ними заключается в том, что происходит с экземпляром, который передается функции. update пытается повторно присоединить экземпляр, это означает, что в данный момент не должно быть другого экземпляра постоянного объекта, присоединенного к сеансу, в противном случае выдается исключение. Однако merge просто копирует все значения в постоянный экземпляр в сеансе (который будет загружен, если он еще не загружен). Входной объект не изменен. Таким образом, слияние является более общим, чем обновление, но может использовать больше ресурсов.
источник
save() - If an INSERT has to be executed to get the identifier, then this INSERT happens immediately, no matter if you are inside or outside of a transaction. This is problematic in a long-running conversation with an extended Session/persistence context.
Подскажите, пожалуйста, как может происходить вставка вне сеанса и почему это плохо?INSERT
. Следовательно, в этих случаях вы не можете вернуть идентификатор прямо сейчас без его генерации, и чтобы сгенерировать его, вы должны запустить егоINSERT
прямо сейчас . Поскольку длительная транзакция выполняется не сейчас, а только при фиксации, единственный способ выполнитьINSERT
now - запустить ее вне tx.Эта ссылка хорошо объясняет:
http://www.stevideter.com/2008/12/07/saveorupdate-versus-merge-in-hibernate/
У всех нас есть те проблемы, с которыми мы сталкиваемся достаточно редко, поэтому, когда мы видим их снова, мы знаем, что решили это, но не можем вспомнить как.
NonUniqueObjectException, выброшенное при использовании Session.saveOrUpdate () в Hibernate, является одним из моих. Я буду добавлять новые функции в сложное приложение. Все мои юнит-тесты работают нормально. Затем, тестируя пользовательский интерфейс, пытаясь сохранить объект, я начинаю получать исключение с сообщением «другой объект с таким же значением идентификатора уже был связан с сеансом». Вот пример кода из Java Persistence с Hibernate.
Чтобы понять причину этого исключения, важно понять отдельные объекты и что происходит, когда вы вызываете saveOrUpdate () (или просто update ()) для отдельного объекта.
Когда мы закрываем отдельный сеанс Hibernate, постоянные объекты, с которыми мы работаем, отсоединяются. Это означает, что данные все еще находятся в памяти приложения, но Hibernate больше не отвечает за отслеживание изменений в объектах.
Если мы затем изменим наш отсоединенный объект и захотим обновить его, мы должны снова присоединить объект. В ходе этого процесса присоединения Hibernate проверит наличие других копий того же объекта. Если он что-то находит, он должен сказать нам, что больше не знает, что такое «настоящая» копия. Возможно, другие изменения были внесены в те другие копии, которые мы ожидаем сохранить, но Hibernate не знает о них, потому что в то время не управлял ими.
Вместо сохранения, возможно, неверных данных, Hibernate сообщает нам о проблеме через исключение NonUniqueObjectException.
Так что же нам делать? В Hibernate 3 у нас есть merge () (в Hibernate 2 используйте saveOrUpdateCopy ()). Этот метод заставит Hibernate скопировать любые изменения из других отдельных экземпляров в экземпляр, который вы хотите сохранить, и, таким образом, объединит все изменения в памяти перед сохранением.
Важно отметить, что слияние возвращает ссылку на недавно обновленную версию экземпляра. Это не присоединение предмета к сессии. Если вы проверите на равенство экземпляров (item == item3), вы обнаружите, что в этом случае он возвращает false. С этого момента вы, вероятно, захотите поработать с item3.
Также важно отметить, что Java Persistence API (JPA) не имеет концепции отдельных и повторно присоединенных объектов и использует EntityManager.persist () и EntityManager.merge ().
В целом я обнаружил, что при использовании Hibernate saveOrUpdate () обычно достаточно для моих нужд. Обычно мне нужно использовать слияние только тогда, когда у меня есть объекты, которые могут иметь ссылки на объекты того же типа. Совсем недавно причина исключения была в коде, подтверждающем, что ссылка не была рекурсивной. Я загружал тот же объект в мою сессию как часть проверки, вызывая ошибку.
Где вы столкнулись с этой проблемой? Работает ли Merge для вас или вам нужно другое решение? Вы предпочитаете всегда использовать слияние, или предпочитаете использовать его только по мере необходимости для конкретных случаев
источник
На самом деле разница между hibernate
save()
иpersist()
методами зависит от класса генератора, который мы используем.Если наш класс генератора назначен, то нет разницы между методами
save()
аpersist(
). Поскольку генератор «назначен» означает, что как программисту нам нужно дать значение первичного ключа для сохранения в праве на базу данных [Надеюсь, вы знакомы с этой концепцией генераторов] В случае, если класс генератора не назначен, предположим, что если имя нашего класса генератора равно «Приращение» означает hibernate it self назначит значение идентификатора первичного ключа в праве базы данных [кроме назначенного генератора, hibernate используется только для обеспечения запоминания значения идентификатора первичного ключа], поэтому в этом случае, если мы вызовем методsave()
илиpersist()
метод, он вставит запись в база данных в норме. Но, слышим,save()
метод может возвращать значение идентификатора первичного ключа, сгенерированное hibernate, и мы можем увидеть егоВ этом же случае
persist()
никогда не вернет клиенту никакого значения.источник
Я нашел хороший пример, показывающий различия между всеми методами сохранения в спящем режиме:
http://www.journaldev.com/3481/hibernate-session-merge-vs-update-save-saveorupdate-persist-example
Вкратце, по вышеуказанной ссылке:
спасти()
сохраняются ()
saveOrUpdate ()
Может использоваться с транзакцией или без нее, и точно так же, как save (), если она используется без транзакции, сопоставленные сущности не будут сохранены до, иначе мы сбросим сеанс.
Результаты в запросах вставки или обновления на основе предоставленных данных. Если данные присутствуют в базе данных, выполняется запрос на обновление.
Обновить()
слияния ()
Также для практических примеров всего этого, пожалуйста, обратитесь к ссылке, которую я упомянул выше, она показывает примеры для всех этих различных методов.
источник
Как я объяснил в этой статье , вы должны предпочитать методы JPA большую часть времени, и
update
для задач пакетной обработки.Объект JPA или Hibernate может находиться в одном из следующих четырех состояний:
Переход из одного состояния в другое осуществляется с помощью методов EntityManager или Session.
Например, JPA
EntityManager
предоставляет следующие методы перехода состояния объекта.Hibernate
Session
реализует всеEntityManager
методы JPA и предоставляет некоторые дополнительные методы перехода состояния объекта, такие какsave
,saveOrUpdate
иupdate
.упорствовать
Чтобы изменить состояние сущности с Transient (New) на Managed (Persisted), мы можем использовать
persist
метод, предложенный JPA,EntityManager
который также наследуется HibernateSession
.Поэтому при выполнении следующего теста:
Hibernate генерирует следующие операторы SQL:
Обратите внимание, что объект
id
назначается до присоединенияBook
объекта к текущему контексту постоянства. Это необходимо, потому что управляемые объекты хранятся вMap
структуре, где ключ формируется типом объекта и его идентификатором, а значение является ссылкой на объект. По этой причине JPAEntityManager
и HibernateSession
известны как кэш первого уровня.При вызове
persist
сущность присоединяется только к текущему контексту постоянства, и INSERT может быть отложено доflush
.Единственным исключением является генератор IDENTITY, который сразу же запускает INSERT, поскольку это единственный способ получить идентификатор сущности. По этой причине Hibernate не может выполнять пакетную вставку для объектов, использующих генератор IDENTITY. Для более подробной информации по этой теме, проверьте эту статью .
Сохранить
Специфичный для Hibernate
save
метод предшествует JPA, и он доступен с начала проекта Hibernate.Чтобы увидеть, как
save
работает метод, рассмотрим следующий тестовый пример:При выполнении приведенного выше теста Hibernate генерирует следующие операторы SQL:
Как видите, результат идентичен
persist
вызову метода. Однако, в отличие от этогоpersist
,save
метод возвращает идентификатор объекта.Для более подробной информации, проверьте эту статью .
Обновить
Специфичный для Hibernate
update
метод предназначен для обхода механизма грязной проверки и принудительного обновления сущности во время сброса.Чтобы увидеть, как
update
работает метод, рассмотрим следующий пример, в которомBook
сущность сохраняется в одной транзакции, затем она модифицирует ее, пока сущность находится в отсоединенном состоянии, иupdate
вызывает SQL UPDATE, используя вызов метода.При выполнении приведенного выше теста Hibernate генерирует следующие операторы SQL:
Обратите внимание, что
UPDATE
выполняется во время сброса Постоянного контекста, непосредственно перед фиксацией, и поэтомуUpdating the Book entity
сообщение регистрируется первым.Использование,
@SelectBeforeUpdate
чтобы избежать ненужных обновленийТеперь ОБНОВЛЕНИЕ всегда будет выполняться, даже если объект не был изменен в отключенном состоянии. Чтобы предотвратить это, вы можете использовать
@SelectBeforeUpdate
аннотацию Hibernate, которая будет вызыватьSELECT
оператор, который получилloaded state
который затем используется механизмом грязной проверки.Итак, если мы аннотируем
Book
сущность с@SelectBeforeUpdate
аннотацией:И выполните следующий контрольный пример:
Hibernate выполняет следующие операторы SQL:
Обратите внимание, что на этот раз не
UPDATE
выполняется, так как механизм грязной проверки Hibernate обнаружил, что объект не был изменен.SaveOrUpdate
Специфичный для Hibernate
saveOrUpdate
метод - это просто псевдоним дляsave
иupdate
.Теперь вы можете использовать,
saveOrUpdate
когда хотите сохранить сущность или форсировать,UPDATE
как показано в следующем примере.Остерегайтесь
NonUniqueObjectException
Одна из проблем, которая может возникнуть при использовании
save
,update
иsaveOrUpdate
заключается в том, что контекст постоянства уже содержит ссылку на сущность с тем же идентификатором и того же типа, что и в следующем примере:Теперь, выполняя приведенный выше тестовый пример, Hibernate собирается выбросить a,
NonUniqueObjectException
потому что второйEntityManager
уже содержитBook
сущность с тем же идентификатором, что и тот, который мы передаемupdate
, и контекст постоянства не может содержать два представления одной и той же сущности.Объединить
Чтобы избежать этого
NonUniqueObjectException
, вам нужно использоватьmerge
метод, предложенный JPAEntityManager
и унаследованный HibernateSession
.Как объясняется в этой статье ,
merge
выборочный снимок новой сущности извлекается из базы данных, если в контексте постоянства не найдена ссылка на сущность, и копирует состояние отсоединенной сущности, переданнойmerge
методу.Чтобы увидеть, как
merge
работает метод, рассмотрим следующий пример, в которомBook
объект сохраняется в одной транзакции, затем он модифицирует его, пока объект находится в отключенном состоянии, и передает отсоединенный объектmerge
в контекст постоянства подпоследовательности.При выполнении приведенного выше теста Hibernate выполнил следующие операторы SQL:
Обратите внимание, что ссылка на сущность, возвращаемая объектом,
merge
отличается от той, которую мы передалиmerge
методу.Теперь, хотя вы предпочитаете использовать JPA
merge
при копировании состояния отсоединенной сущности, дополнительноеSELECT
может быть проблематичным при выполнении задачи пакетной обработки.По этой причине вы должны предпочесть использовать,
update
если вы уверены, что к текущему контексту персистентности уже не привязана ссылка на сущность и что отсоединенная сущность была изменена.Для более подробной информации по этой теме, проверьте эту статью .
Вывод
Чтобы сохранить сущность, вы должны использовать
persist
метод JPA . Чтобы скопировать состояние отдельного объекта,merge
должно быть предпочтительным. Этотupdate
метод полезен только для задач пакетной обработки.save
ИsaveOrUpdate
просто псевдонимы ,update
и вы не должны , вероятно , использовать их на всех.Некоторые разработчики вызывают
save
даже тогда, когда сущность уже управляется, но это ошибка и вызывает избыточное событие, поскольку для управляемых сущностей UPDATE автоматически обрабатывается во время сброса контекста постоянства.Для более подробной информации, проверьте эту статью .
источник
Имейте в виду, что если вы вызываете обновление для отдельного объекта, в базе данных всегда будет выполняться обновление независимо от того, изменили вы объект или нет. Если это не то, что вы хотите, вы должны использовать Session.lock () с LockMode.None.
Вы должны вызывать update, только если объект был изменен вне области текущего сеанса (в автономном режиме).
источник
Ни один из следующих ответов не является правильным. Все эти методы кажутся похожими, но на практике делают совершенно разные вещи. Трудно давать короткие комментарии. Лучше дать ссылку на полную документацию об этих методах: http://docs.jboss.org/hibernate/core/3.6/reference/en-US/html/objectstate.html
источник
Ни один из ответов выше не является полным. Хотя ответ Лео Теобальда выглядит ближайшим ответом.
Суть в том, как hibernate работает с состояниями сущностей и как он обрабатывает их при изменении состояния. Все должно быть рассмотрено и в отношении сбрасываний и коммитов, которые, кажется, все полностью проигнорировали.
НИКОГДА НЕ ИСПОЛЬЗУЙТЕ ЭКОНОМИЧЕСКИЙ МЕТОД HIBERNATE. ЗАБУДЬТЕ, ЧТО ЭТО ДАЖЕ СУЩЕСТВУЕТ В HIBERNATE!
упорствовать
Как все объяснили, Persist в основном переводит сущность из «переходного» состояния в «управляемое» состояние. На этом этапе слякоть или коммит могут создать оператор вставки. Но сущность все равно останется в «Управляемом» состоянии. Это не меняется с флешем.
В этот момент, если вы снова «упорствуете», никаких изменений не будет. И больше не будет спасений, если мы попытаемся сохранить существующую сущность.
Веселье начинается, когда мы пытаемся выселить сущность.
Выселение - это специальная функция Hibernate, которая переводит сущность из «Управляемого» в «Отделенный». Мы не можем вызвать упорство на отдельном объекте. Если мы это сделаем, то Hibernate вызовет исключение, и вся транзакция будет откатана при фиксации.
Слияние с обновлением
Это две интересные функции, которые делают разные вещи, когда рассматриваются по-разному. Оба они пытаются перевести сущность из состояния «Отключено» в состояние «Управляемый». Но делать это по-другому.
Поймите факт, что Detached означает своего рода "автономное" состояние. и управляемый означает «онлайн» состояние.
Соблюдайте код ниже:
Когда ты это делаешь? Как ты думаешь, что произойдет? Если вы сказали, что это вызовет исключение, то вы правы. Это вызовет исключение, потому что, слияние сработало на объекте объекта, который является отделенным состоянием. Но это не меняет состояние объекта.
За сценой слияние вызовет запрос выбора и в основном возвращает копию объекта, который находится в присоединенном состоянии. Соблюдайте код ниже:
Приведенный выше пример работает, потому что слияние принесло новую сущность в контекст, который находится в постоянном состоянии.
При применении с обновлением то же самое работает нормально, потому что обновление на самом деле не приносит копию объекта, как слияние.
В то же время в трассировке отладки мы видим, что Update не вызвал SQL-запрос select как merge.
Удалить
В приведенном выше примере я использовал удаление, не говоря об удалении. Удаление в основном переводит объект из управляемого состояния в состояние «удалено». А при сбросе или подтверждении выдаст команду удаления для сохранения.
Однако возможно вернуть объект в «управляемое» состояние из «удаленного» состояния, используя метод persist.
Надеюсь, приведенное выше объяснение прояснило любые сомнения.
источник