← Назад к вопросам

Что такое жизненный цикл сущности в Hibernate?

2.0 Middle🔥 151 комментариев
#ORM и Hibernate

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Жизненный цикл сущности в Hibernate

Жизненный цикл сущности (Entity Lifecycle) в Hibernate — это последовательность состояний, через которые проходит объект от создания до удаления. Понимание этого цикла критично для эффективной работы с ORM и избежания ошибок.

Четыре состояния жизненного цикла

1. Transient (Новая, не управляемая)

Объект существует только в памяти приложения, Hibernate о нём ничего не знает.

User user = new User();
user.setName("Ivan");
user.setEmail("ivan@example.com");
// Объект в состоянии Transient
// Hibernate его не отслеживает
// В БД записи нет

Характеристики Transient:

  • Нет ID/первичного ключа
  • Не отслеживается Session
  • Нет соответствия в БД
  • При GC объект будет удален

2. Persistent (Управляемая/Персистентная)

Объект управляется Hibernate Session и имеет соответствие в БД.

Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();

User user = new User();
user.setName("Ivan");
user.setEmail("ivan@example.com");

session.persist(user);  // Переход в Persistent
// или
session.save(user);

tx.commit();

// Объект теперь Persistent
// Имеет ID
// Отслеживается Session
// Соответствует записи в БД

Характеристики Persistent:

  • Управляется Session
  • Имеет ID/первичный ключ
  • Любые изменения отслеживаются
  • При commit изменения сохранятся в БД
  • Lazy loading работает

3. Detached (Отсоединённая)

Объект был Persistent, но Session был закрыт или объект был явно отсоединён.

User user = session.get(User.class, 1L); // Persistent
session.close(); // Объект становится Detached

// Теперь user в состоянии Detached
// Session о нём не знает
// Изменения не будут отслеживаться

user.setName("New Name"); // Изменение НЕ будет сохранено

Отсоединение может быть явным:

Session session = sessionFactory.openSession();
User user = session.get(User.class, 1L);
session.detach(user); // Явное отсоединение
session.evict(user);  // Альтернатива
session.clear();      // Отсоединить все объекты

Характеристики Detached:

  • Имеет ID (был когда-то Persistent)
  • НЕ управляется Session
  • Изменения НЕ отслеживаются автоматически
  • При присоединении (attach) может вернуться в Persistent

4. Removed (Удалённая)

Объект отмечен для удаления и будет удален при commit.

Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();

User user = session.get(User.class, 1L); // Persistent
session.remove(user); // Переход в Removed
// или
session.delete(user);

tx.commit(); // SQL DELETE выполнится

// После commit объект становится Detached

Характеристики Removed:

  • Отмечена для удаления
  • Всё ещё управляется Session (временно)
  • При commit будет выполнен DELETE

Диаграмма переходов между состояниями

Transient
   |
   |-- save()/persist() --> Persistent <-- merge()/update()
                                |
                                |-- close()/detach() --> Detached
                                |
                                |-- delete()/remove() --> Removed
                                                            |
                                                            |-- commit() --> Detached

Практические примеры переходов

Пример 1: Полный цикл

Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();

// 1. Transient
User user = new User();
user.setName("Alex");

// 2. Persistent
session.persist(user);
system.out.println("ID = " + user.getId()); // ID сгенерирован

// Изменение отслеживается
user.setName("Alexander");

tx.commit(); // UPDATE будет выполнен
session.close();

// 3. Detached
user.setName("Alex"); // Изменение НЕ сохранится

Пример 2: Повторное присоединение (Reattach)

Session session1 = sessionFactory.openSession();
User user = session1.get(User.class, 1L); // Persistent
session1.close(); // Detached

// Позже, в другой Session
Session session2 = sessionFactory.openSession();
Transaction tx = session2.beginTransaction();

user.setName("New Name");
session2.merge(user); // Или update(user)
// Объект снова Persistent в session2

tx.commit();

Пример 3: Cascade операции

@Entity
public class Post {
    @OneToMany(cascade = CascadeType.ALL)
    private List<Comment> comments;
}

// Удаление Post удалит и все Comment (Cascade)
Post post = session.get(Post.class, 1L); // Persistent
session.delete(post); // Removed
// Все comments также перейдут в Removed

Важные методы Session

МетодДействиеРезультат
persist()Transient → PersistentINSERT
save()Transient → PersistentINSERT
update()Detached → PersistentUPDATE
merge()Detached → PersistentUPDATE (создаёт новый объект)
delete()Persistent → RemovedDELETE
remove()Persistent → RemovedDELETE
get()FetchPersistent или null
load()Lazy loadPersistent (proxy)
detach()Persistent → DetachedОтсоединение
clear()Persistent → DetachedОтсоединить все

Критические ошибки

Ошибка 1: Использование Detached объекта без merge

Session session1 = sessionFactory.openSession();
User user = session1.get(User.class, 1L);
session1.close();

Session session2 = sessionFactory.openSession();
session2.update(user); // Ошибка! user Detached
// Нужно:
session2.merge(user);

Ошибка 2: Забыли commit

Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();
User user = new User();
session.persist(user);
// tx.commit() забыли!
session.close(); // Изменения потеряны

Ошибка 3: Использование closed Session

Session session = sessionFactory.openSession();
User user = session.get(User.class, 1L); // Persistent
session.close();
user.getName(); // OK
user.getComments().size(); // LazyInitializationException!
// Collections инициализируются с Session

Решение:

// Инициализировать до close
Hibernate.initialize(user.getComments());
session.close();
user.getComments().size(); // OK

Граница транзакции и сессии

Open Session In View (OSIV) — паттерн для web-приложений:

// Spring Data выглядит как это работает внутри
public List<User> getAllUsers() {
    // Session открыта
    return userRepository.findAll();
    // Session закрывается (Detached)
}

// В контроллере
List<User> users = getAllUsers(); // Detached
users.get(0).getComments().size(); // LazyInitializationException!

Заключение

Жизненный цикл сущности — это фундамент Hibernate. Ключевые моменты:

  • Transient — новый объект, Session не знает
  • Persistent — управляется Session, изменения отслеживаются
  • Detached — был Persistent, Session закрыта
  • Removed — отмечен для удаления

Понимание переходов помогает избежать LazyInitializationException, Lost Updates и других проблем с ORM.

Что такое жизненный цикл сущности в Hibernate? | PrepBro