JavaRush/Курсы/Модуль 4. Работа с БД/Как изменить объект в Hibernate

Как изменить объект в Hibernate

Открыта

Нюансы работы метода merge()

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

Во-первых, это метод merge(), который обновляет информацию в базе на основе переданного объекта. При этом будет вызван SQL-запрос UPDATE. Пример:

User user = new User();
user.setName("Колян");
session.save(user);

session.evict(user);     // отсоединяем объект от сессии
user.setName("Маша");

User user2 = (User) session.merge(user);

Тут есть несколько важных нюансов.

Во-первых, метод merge() возвращает результат – обновленный объект. Этот объект имеет состояние Persist и присоединен к объекту session. Объект передаваемый в метод merge() при этом не меняется.

Может показаться, что между user и user2 нет разницы, но это не так. В метод merge() можно передать POJO объект, а в качестве результата метод может вернуть proxy (зависит от настроек Hibernate). Поэтому просто запомни, что метод merge() не меняет передаваемый объект.

Во-вторых, если объект передаваемый в merge() имеет статус Transient (и у него нет ID), то для него создастся отдельная строчка в базе данных. Другими словами будет выполнена команда persist().

В-третьих, если в метод merge() передать объект уже присоединенный к сессии (со статусом Persist), то ничего не произойдет – метод просто вернет этот же объект. Почему? А все потому, что при коммите транзакции данные и так запишутся в базу:

User user = new User();
user.setName("Колян");
session.save(user);

user.setName("Маша"); //меняем объект присоединенный к сессии

session.close();  //в базу запишутся все измененные объекты

Не нужно сохранять каждый раз объект после любых его изменений. Если этот объект в статусе Persist, то Hibernate все сделает сам. Если вы меняете объект, который “присоединен к базе”, то все его изменения будут записаны в базу.

Нюансы работы метода update()

Также у Hibernate есть метод update(), который как и метод save() достался ему от предыдущих версий. С помощью этого метода можно только обновить данные уже сохраненного объекта. При этом будет вызван SQL-запрос UPDATE. Пример:

User user = new User();
user.setName("Колян");
session.save(user);

session.evict(user);     // отсоединяем объект от сессии
user.setName("Маша");

session.update(user);

Этот метод ничего не возвращает и не меняет существующий объект.

Если вызвать этот метод для нового объекта, то просто кинется исключение:

User user = new User();
user.setName("Колян");
session.update(user);   //тут кинется исключение

Метод saveOrUpdate()

До появления JPA функцию метода persist() выполнял метод saveOrUpdate(). Его задачей было обновить в базе информацию по существующему объекту, а если такового нет, то создать его. Его почти всегда используют вместо методов save() и update().

В отличии от метода update(), он может менять передаваемый ему объект. Например, установить ему ID, который был присвоен при сохранении в базу данных. Пример:

User user = new User();
user.setName("Колян");
session.saveOrUpdate(user);   //объект будет записан в базу

Как это работает:

  • если у передаваемого объекта установлен ID, то вызывается SQL-метод UPDATE
  • если у передаваемого объекта ID не установлен, то вызывается SQL-метод INSERT
1
Задача
Модуль 4. Работа с БД,  11 уровень2 лекция
Недоступна
Сохрани или обнови
Сохрани или обнови
Комментарии (12)
  • популярные
  • новые
  • старые
Для того, чтобы оставить комментарий Вы должны авторизоваться
Дмитрий
Уровень 37
16 марта 2024, 17:39
кто нибудь сталкивался с проблемой, что хибер генерирует delete/insert вместо ожидаемого update объекта? Почему так происходит, как это можно решить? Работаю со spring-boot-data-jpa, postgresql. Использую метод save() репозитория
13 мая 2023, 06:38
Вот это: User user = new User(); user.setName("Колян"); session.save(user); user.setName("Маша"); //меняем объект присоединенный к сессии session.close(); //в базу запишутся все измененные объекты не работает. Ничего в базу не пишется без открытия и закрытия транзакции.
Andrey Vysotsky
Уровень 32
19 апреля 2024, 14:00
У меня тоже с этого бомбануло малость, благо дружище чат гпт если в него тупо закинуть весь свой год подсказывает, что нужно сделать вот так: Вы открываете сеанс с помощью sessionFactory.openSession(), но не начинаете транзакцию с помощью session.beginTransaction() и не закрываете её с помощью session.getTransaction().commit(). Без этого Hibernate не будет фиксировать изменения в базе данных. В вашем случае достаточно добавить session.beginTransaction() перед session.persist(mappingTest) и session.getTransaction().commit() после этого вызова. Вообще, оказывется, что учиться по ДжаваРашу с чатом гпт куда удобнее - если в лекции в очередной раз навалили дерьма которое не бьется с тем что ты уже прошел, чат гпт понятно все разъяснит и подскажет что ты пропустил.
Ольга Николенко
Уровень 115
Expert
28 мая 2024, 19:10
Эта информация давалась на прошлых лекциях, если вы производите изменения в БД - создание транзакции строго обязательно. Так то тут в примерах везде использование объекта session без его создания, это минимальный код для примеров.
Роман
Уровень 88
11 января 2025, 04:08
Конкретно в данном случае претензии к джаварашу не обоснованы. Про транзакции расписывали в одной из прошлых лекций и потом еще напоминали про них. Плюс достаточно даже просто задачу открыть, чтобы обнаружить там их.
Дмитрий
Уровень 88
Expert
8 марта, 20:38
Вероятно поправили код примера, т.к. там уже есть начало транзакции и commit, но претензии обоснованы были, ибо я сюда пришел не за минимализмом в примерах, а за полноценным описанием и полноценными примерами, согласен, в том что информация была в пред урокам о начале и закрытии транзакции, НО если авторы пропускают некоторые моменты в примерах, то желательно подсвечивать этот момент по типу "в этом месте подумай что надо добавить еще", а не только описание методов в лоб, которые надо добавить
Misha Saharin
Уровень 111
Expert
3 мая 2023, 12:08
как будто Id это типа hashCode(), как способ быстро сообщить коротко о состоянии обьекта, перед тем как провести здоровый и полноценный (одновременно энергозатратный и емкий) equals()?
5 апреля 2023, 22:04
дэк какой использовать?
рост
Уровень 32
27 февраля 2023, 16:15
дыаааааа это то что я искал
Владимир
Уровень 109
Expert
28 декабря 2022, 21:21
От hibernate кругом голова Влюбись — хлопот не оберёшься
aDuVaN4Ik
Уровень 42
15 января 2023, 20:02
В точку
Ольга Николенко
Уровень 115
Expert
28 мая 2024, 18:54
как говорил папаша мой)