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

Спящий режим: нижняя сторона слияния() над обновлением()

У меня возникают проблемы с NonUniqueObjectException, сбрасываемыми с помощью Hibernate.

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

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

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

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

4b9b3361

Ответ 1

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

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

Что является недостатком использования функции merge() over 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");

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

  • Добавить столбец версии (@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?

Ответ 2

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

Ответ 3

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 и закрыли session1 в строке 7, так что теперь объект s1 в кеше session1 будет уничтожен, поскольку кеш сеанса1 истечет, когда мы говорим session1.close().

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

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