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

Как сохранить объект в Hibernate

Открыта

Возможные варианты статуса объекта

Как ты уже наверное обратил внимание, когда объект присоединен к Hibernate, его состояние называется Persistent или Managed. Как правильно? Persist или Managed?

Можно и так, и так. Согласно спецификации JPA объект имеет статус Persist, а согласно спецификации Hibernate его состояние называется Managed.

В Hibernate работа с базой ведется через объект типа org.hibernate.Session. Согласно же JPA класс должен называться javax.persistence.EntityManager. На самом деле большой проблемы тут нет, так как оба типа являются интерфейсами.

Интерфейс org.hibernate.Session объявлен так:

interface Session extends java.lang.AutoCloseable, javax.persistence.EntityManager, HibernateEntityManager,    QueryProducer, java.io.Serializable, SharedSessionContract {

}

Поэтому в интерфейсе Session есть все методы, которые есть в интерфейсе EntityManager. Но также есть и свои, которые достались ему от более ранних версий Hibernate, когда еще не было спецификации JPA.

Описывается эта вся ситуация вот такой картинкой:

Давай же разберем все методы, которые есть у интерфейса session, а также нюансы их работы.

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

При сохранении объекта в базу данных тебе нужно помнить две вещи.

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

Давай рассмотрим какую-нибудь простую ситуацию, например, у тебя есть класс User:

@Entity
public class User {
	@Id
	@GeneratedValue
    public Integer id;

	@Columnt(name=”user_name”)
    public String name;
}

Давай сохраним в базу его объект с помощью метода persist().

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

Задача этого метода сохранить в базу данных новый объект. Если такого объекта еще нет, то он будет добавлен в базу через вызов SQL-метода INSERT.

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

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

session.evict(user);     // отсоединяем объект от сессии
session.persist(user); // тут кинется исключение PersistenceException!

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

Метод save() достался нынешнему Hibernate от его предыдущих версий. По своей сути он очень похож на метод persist(), он тоже добавляет новую запись в таблицу с помощью метода INSERT. Однако у него есть несколько интересных нюансов.

Во-первых, этот метод возвращает значение – новое ID объекта. Как ты уже знаешь, обычно до добавления в базу у объектов нет ID и оно присваивается уже базой данных. Так вот, метод save() объекта session возвращает ID, которая была присвоена сохраняемому объекту.

Важно! Согласно спецификации Hibernate ID может быть любой сериализуемый объект, не только число. Это может быть строка, число, enum, вообще что угодно, что можно целиком положить в одну колонку таблицы в базе.

Метод save() имеет тип результата Serialized, поэтому его результат нужно приводить к правильному типу:

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

Также у метода save() другое поведение в случае с Detached состоянием объекта. Такой объект он рассматривает как новый и просто добавляет еще одну запись:

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

session.evict(user); 	// отсоединяем объект от сессии
Integer id2 = (Integer) session.save(user);

Переменные id и id2 будут отличаться. В таблице в базе данных будут добавлены две записи: по одной для каждой операции save().

1
Задача
Модуль 4. Работа с БД,  11 уровень1 лекция
Недоступна
Отсоединяем объект от сессии
Отсоединяем объект от сессии
Комментарии (17)
  • популярные
  • новые
  • старые
Для того, чтобы оставить комментарий Вы должны авторизоваться
Андрей
Уровень 1
4 июня 2025, 10:21
В Hibernate 7.0.0 Final метод Session.save() был полностью удалён из API. Это означает, что попытки его использования приведут к ошибкам компиляции, и IntelliJ IDEA будет подсвечивать его как недоступный. Ранее этот метод был помечен как устаревший в версии Hibernate 6.0, а начиная с версии 7.0 — полностью исключён из интерфейса Session Вместо метода save() рекомендуется использовать persist(). Однако следует учитывать, что persist() не возвращает идентификатор сущности. Если вам необходимо получить ID после сохранения, вы можете воспользоваться методом getId() вашей сущности, при условии, что ID генерируется автоматически.
СтудентJava
Уровень 109
14 февраля 2025, 13:32
не понимаю, в задачи написано что бы выводилось folse но выводится у меня true и решение проходит
СтудентJava
Уровень 109
14 февраля 2025, 13:55
Разобрался почему выводится true. У меня нет подключение к реальной базе данных MySQL. Поэтому когда я в id1 записываю animal и он присваивает ему номер 1 затем после вызова evict удаляет объект animal из кэша сессии то в id2 он снова присваивает 1. Так как нет подключения к какой либо СУБД
1 февраля 2025, 02:49
Во-первых, сохранение объекта в итоге приведет к выполнению одной из команд SQL: INSERT или UPDATE - для чего это помещено в описании метода persist() ? UPDATE и persist() как связаны? 😒
Олег
Уровень 106
Expert
12 октября 2024, 12:43
Всё понял.
Роман
Уровень 88
11 января 2025, 03:43
красавец
Дмитрий
Уровень 37
16 марта 2024, 17:21
Еще бы хотелось пояснить по поводу id. Если они генерятся на стороне бд и мы вызвали методы save, а транзакция не закончена, хибернейт в этот момент запросов в бд не делает, а id готов вернуть, как?
Дмитрий
Уровень 37
16 марта 2024, 17:17
Если быть точным, то изменения будут отправлены в бд не после закрытия транзакции, а в момент ее закрытия. То есть новая транзакция создана не будет и запросы улетят в бд в рамках той же транзакции в которой и работали
Дмитрий
Уровень 37
16 марта 2024, 17:15
Требуется нормальный комментарий к схеме "Detached object"! Из не вообще не понятно, что автор пытается донести. Что объект не имеет статус persist, если не был получен из базы, а только крутится в сессии?
Mila
Уровень 102
12 января 2024, 04:42
Когда мы первый раз сохраняем объект animal, мы получаем его идентификатор. После исключения методом evict объекта из сессии, Hibernate этот объект больше не отслеживает. Затем мы снова сохраняем тот же объект, но т.к он ранее был исключен из сессии, Hibernate присваивает ему новый идентификатор. При сравнении должно возвращать false, тк объект был сохранен дважды как два разных экземпляра. Почему возвращает true? Потому что таблицы animal_table нет в схеме. Hibernate не может сохранить объект из-за ошибки, он не присваивает новый id сущности. id1 и id2 были объявлены, но не инициализированы. В случае отсутствия инициализации они получают значение по умолчанию, т.е 0. После неудавшихся попыток сохранения обе переменные = 0. Чтобы исправить ситуацию, можно создать таблицу с помощью properties.put(Environment.HBM2DDL_AUTO, "update") - это автоматически создаст таблицу в соответствии с аннотациями. Также поменять диалект properties.put(Environment.DIALECT, "org.hibernate.dialect.MySQL5Dialect");
Max Dudin
Уровень 6
Expert
5 октября 2023, 09:26
на 05.10.2023 ситуация такая.... они равны ...вы ход true =))) (они равны и в референсном решении) =))) но валидацию задача проходит на ура с зачтение пункта "значение id1 и id2 должны быть разные" прикольно, но всё таки почему они одинаковые?
Дмитрий
Уровень 111
Expert
26 октября 2023, 22:01
На 27.10.23 разные.
Алексей
Уровень 1
Expert
12 декабря 2023, 08:17
12.12.23 true
Павел
Уровень 19
Expert
21 марта 2024, 15:04
Не надо смотреть на дату. Смотрите на сообщения консоли Хибернейта. Мне пришлось вручную сохранять две таблицы через консоль mysql.
create table test.animal_table
(
    id int,
    name varchar(30),
    age int,
    family varchar(30)
);
create table test.animal_table_SEQ
(
    next_val int
);
тогда получится так Это я как слабо разбирающийся в Хибернейт говорю.
Ольга
Уровень 108
Expert
6 сентября 2023, 10:53
И с этой задачей что-то не так. Даже при тотальном копировании правильного ответа задача не принимается с ошибкой, что id у вас не отличаются (3 пункт проверки). Надо бы задачи этого раздела все пересмотреть, кучность косяков возрастает.