Hibernate: недостаток слияния () по сравнению с обновлением ()

У меня проблемы с NonUniqueObjectException брошенный Hibernate.

Читая документы и этот пост в блоге, я заменил звонок с update() в merge()и это решило проблему.

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

Мой вопрос: учитывая, что merge() всегда разрешает объект сеанса или извлекает его, если он не существует, вызывает merge(), как правило, более безопасную альтернативу, чем update()?

В чем недостаток использования merge() над update()?

3 ответа

Решение

Является ли вызов merge() вообще более безопасной альтернативой, чем update()?

Как способ избежать исключения NonUniqueObjectException, да. Я думаю, это объясняет, почему JPA не разрешает метод обновления.

В чем недостаток использования merge() вместо update()?

Пользователь, не прошедший консультации, может подумать, что он или она имеет новый управляемый объект. Что-то вроде

// myEntity (passed as parameter does not become managed)
// Only the one returned by the merge operation is a managed entity
session.merge(myEntity);

// "newValue" is not commited because myEntity is not managed
myEntity.setMyProperty("newValue");

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

  • Добавить версию (@Version) столбца. 0 или NULL версия указывает, что экземпляр является новым и должен быть вставлен, а не обновлен
  • Используйте перехватчик Hibernate
  • Если вы уверены, что хотите обновить вместо вставки, вы можете использовать следующий подход

...

public void updateMyEntity(MyEntity updateableMyEntity);

    // load does not hit the database
    MyEntity myEntity = (MyEntity) session.load(MyEntity.class, updateableMyEntity.getId());

    BeanUtils.copyProperties(myEntity, updateableMyEntity);

}

Таким образом, вы можете обновить вашу сущность без слияния или обновления метода. См. Этот вопрос для получения дополнительной информации: Лучший способ обновить некоторые поля отдельного объекта в Hibernate?

Используйте update(), если вы уверены, что сеанс не содержит уже существующего экземпляра с тем же идентификатором, и merge(), если вы хотите объединить свои изменения в любое время без учета состояния сеанса. Другими словами, update() обычно является первым методом, который вы вызываете в новом сеансе, гарантируя, что присоединение ваших отсоединенных экземпляров является первой выполняемой операцией.

SessionFactory factory = cfg.buildSessionFactory();

Session session1 = factory.openSession();
Student s1 = null;
Object o = session1.get(Student.class, new Integer(101));
s1 = (Student)o;
session1.close();
s1.setMarks(97);

Session session2 = factory.openSession();
Student s2 = null;
Object o1 = session2.get(Student.class, new Integer(101));
s2 = (Student)o1;

Transaction tx=session2.beginTransaction();
session2.merge(s1);

объяснение

Как видно из строк 4–7, мы только что загрузили один объект s1 в кэш сеанса 1 и закрыли сеанс 1 в строке 7, так что теперь объект s1 в кеше сеанса 1 будет уничтожен, поскольку срок действия кеша сеанса 1 истечет, когда мы скажем session1.close(),

Теперь объект s1 будет находиться в некотором месте в ОЗУ, а не в кеше session1. Здесь s1 находится в отдельном состоянии, и в строке номер 8 мы изменили этот отдельный объект s1, теперь, если мы вызываем update() Затем метод hibernate выдаст ошибку, потому что мы можем обновить объект только в сеансе.

Поэтому мы открыли еще один сеанс [session2] в строке № 10 и снова загрузили тот же объект ученика из базы данных, но с именем s2. Итак, в этой сессии2 мы назвали session2.merge(s1); теперь в s2 объект s1 изменения будут объединены и сохранены в базе данных

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