Подтвердить что ты не робот

Hibernate saveOrUpdate поведение

Кто-нибудь знает, как Hibernate знает, следует ли вводить INSERT или ОБНОВИТЬ значение в базе данных при вызове session.saveOrUpdate()?

До сих пор я решил, что он не зависит от информации в кеше и что существование объекта в базе данных определяется первичным ключом.

4b9b3361

Ответ 1

При использовании .saveOrUpdate() Hibernate будет проверять, является ли объект переходным (он не имеет свойства идентификатора), и если это так, он сделает его постоянным, генерируя его идентификатор и назначая его сеансу. Если объект уже имеет идентификатор, он выполнит .update().

Из документации:

saveOrUpdate() выполняет следующие действия:

  • если объект уже является постоянным в этой сессии ничего не делать
  • если другой объект, связанный с сессия имеет тот же идентификатор, исключить исключение
  • если объект не имеет идентификатора свойство, save() it
  • если идентификатор объекта имеет значение, присвоенное недавно экземпляр объекта, save() it
  • если объект управляется версией  или, и значение свойства версии одинаково значение, присвоенное недавно экземпляр объекта, save() it иначе update() объект

Ответ 2

Возможно, полезно привести библейскую версию Hibernate (Java Persistence with Hibernate, 2-е изд., стр. 528):

Более опытные пользователи Hibernate используют saveOrUpdate() исключительно; намного проще позволить Hibernate решить, что нового и что старое, особенно в более сложной сети объектов со смешанным состоянием. Единственным (не очень серьезным) недостатком эксклюзивного saveOrUpdate() является то, что он иногда не может догадаться, является ли экземпляр старым или новым без запуска SELECT в базе данных - например, когда класс сопоставляется с естественным составным key и no version или timestamp.

Как Hibernate обнаруживает, какие экземпляры являются старыми и какие новые? Доступен ряд опций. Hibernate предполагает, что экземпляр является несохраненным временным экземпляром, если:

  • Свойство идентификатора null.
  • Свойство version или timestamp (если оно существует) null.
  • Новый экземпляр одного и того же стойкого класса, созданного внутри Hibernate, имеет те же значения идентификатора базы данных, что и данный экземпляр.
  • Вы указываете unsaved-value в документе сопоставления для класса, а значение свойства идентификатора соответствует. Атрибут unsaved-value также доступен для элементов отображения версии и времени.
  • Данные сущности с тем же значением идентификатора не находятся в кэше второго уровня.
  • Если вы проверите экземпляр в своем коде, поставьте реализацию или org.hibernate.Interceptor и верните Boolean.TRUE из Interceptor.isUnsaved().

Ответ 3

Как указано здесь, saveOrUpdate либо сохраняет временный экземпляр, генерируя новый идентификатор, либо обновляет/повторно привязывает отдельные экземпляры, связанные с его текущим идентификатор. Более конкретно:

  • Если объект уже настойчив в этом сеансе, ничего не делайте
  • если другой объект, связанный с сеансом, имеет один и тот же идентификатор, генерирует исключение
  • если объект не имеет свойства идентификатора, save() it
  • если идентификатор объекта имеет значение, назначенное для вновь созданного объекта, save() it
  • если объект имеет версию <version> или <timestamp>, а значение свойства версии
  • то же значение, присвоенное вновь созданному объекту, save() it
  • иначе update() объект

Ответ 4

Это делается на основе значения первичного ключа. Если первичный ключ undefined, значение будет по умолчанию равным 0 для числовых суррогатных ключей и save. Если первичный ключ заполнен, он будет вызывать update.

Ответ 5

Если кто-то действительно не понимает в теории, то есть код

     MyModel sent = myDao.myDaoImpl(id);                 
     if(sent == null){                       
         sent = **new MyModel();** // new Object
         sent.setXX(id);
         sent.setYY("Yes");
         sent.setDate(new Date());
         myDao.saveOrUpdate(sent); // Insert will be called
     }else if(! "Yes".equalsIgnoreCase(sent.getFlag())){
         sent.setXX("Yes");
         sent.setDate(new Date());
         myDao.saveOrUpdate(sent); // Update will be called
     }