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

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

Модуль 4. Работа с БД
11 уровень , 2 лекция
Открыта

Нюансы работы метода 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 лекция
Недоступна
task1102
Сохрани объект animalCat в БД с помощью метода save объекта session, потом вызови метод saveOrUpdate для объектов animalCat и animalDog...
Комментарии (11)
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ
Дмитрий Уровень 37
16 марта 2024
кто нибудь сталкивался с проблемой, что хибер генерирует delete/insert вместо ожидаемого update объекта? Почему так происходит, как это можно решить? Работаю со spring-boot-data-jpa, postgresql. Использую метод save() репозитория
13 мая 2023
Вот это: User user = new User(); user.setName("Колян"); session.save(user); user.setName("Маша"); //меняем объект присоединенный к сессии session.close(); //в базу запишутся все измененные объекты не работает. Ничего в базу не пишется без открытия и закрытия транзакции.
Andrey Vysotsky Уровень 32
19 апреля 2024
У меня тоже с этого бомбануло малость, благо дружище чат гпт если в него тупо закинуть весь свой год подсказывает, что нужно сделать вот так: Вы открываете сеанс с помощью sessionFactory.openSession(), но не начинаете транзакцию с помощью session.beginTransaction() и не закрываете её с помощью session.getTransaction().commit(). Без этого Hibernate не будет фиксировать изменения в базе данных. В вашем случае достаточно добавить session.beginTransaction() перед session.persist(mappingTest) и session.getTransaction().commit() после этого вызова. Вообще, оказывется, что учиться по ДжаваРашу с чатом гпт куда удобнее - если в лекции в очередной раз навалили дерьма которое не бьется с тем что ты уже прошел, чат гпт понятно все разъяснит и подскажет что ты пропустил.
Ольга Николенко Уровень 109 Expert
28 мая 2024
Эта информация давалась на прошлых лекциях, если вы производите изменения в БД - создание транзакции строго обязательно. Так то тут в примерах везде использование объекта session без его создания, это минимальный код для примеров.
Роман Уровень 88
11 января 2025
Конкретно в данном случае претензии к джаварашу не обоснованы. Про транзакции расписывали в одной из прошлых лекций и потом еще напоминали про них. Плюс достаточно даже просто задачу открыть, чтобы обнаружить там их.
Misha Saharin Уровень 111 Expert
3 мая 2023
как будто Id это типа hashCode(), как способ быстро сообщить коротко о состоянии обьекта, перед тем как провести здоровый и полноценный (одновременно энергозатратный и емкий) equals()?
5 апреля 2023
дэк какой использовать?
рост Уровень 32
27 февраля 2023
дыаааааа это то что я искал
Владимир Уровень 109 Expert
28 декабря 2022
От hibernate кругом голова Влюбись — хлопот не оберёшься
aDuVaN4Ik Уровень 42
15 января 2023
В точку
Ольга Николенко Уровень 109 Expert
28 мая 2024
как говорил папаша мой)