Как и когда использовать метод commit() в Hibernate?

Ответ

Метод commit() вызывается у объекта Transaction для фиксации текущей единицы работы в базе данных. Он завершает транзакцию, синхронизируя состояние контекста persistence с БД.

Типичный шаблон использования в чистом Hibernate:

Session session = sessionFactory.openSession();
Transaction transaction = null;
try {
    transaction = session.beginTransaction(); // Начало транзакции

    // Бизнес-логика: работа с сущностями
    Employee emp = new Employee("John Doe", "Engineering");
    session.persist(emp); // Сущность становится управляемой (persistent)

    // ... другие операции

    transaction.commit(); // ФИКСАЦИЯ: все изменения сбрасываются (flush) в БД и транзакция завершается
} catch (Exception e) {
    if (transaction != null) {
        transaction.rollback(); // Откат в случае ошибки
    }
    throw e;
} finally {
    session.close(); // Закрытие сессии
}

Что происходит при вызове commit():

  1. Неявно вызывается session.flush(): все изменения, накопленные в сущностях контекста persistence (сессии), синхронизируются с БД через SQL-операции INSERT, UPDATE, DELETE.
  2. Выполняется SQL-команда COMMIT для текущей транзакции СУБД.
  3. Транзакция Hibernate завершается.

Важно:

  • В Spring-приложениях с @Transactional вызов commit() выполняется автоматически при успешном завершении метода.
  • После commit() управляемые сущности остаются в состоянии persistent, но привязаны к закрытой транзакции. Последующие изменения не будут автоматически сохраняться.
  • Вызов commit() на неактивной транзакции выбросит исключение.

Ответ 18+ 🔞

Давай разберём эту вашу транзакционную магию, а то некоторые думают, что commit() — это такая кнопка «сделать хорошо». Ан нет, сука.

Вот представь: ты в баре (это наша сессия Hibernate). Ты набираешь в долг пива, закусок, ещё кому-то обещаешь налить (это наши persist(), merge(), delete()). Бармен (контекст persistence) всё записывает у себя на листочке, но в кассу (БД) пока не пробивает. Ты сидишь, веселишься — состояние managed, всё ок.

А потом подходит время расплачиваться. Вот этот момент, когда ты говоришь «давайте, чё там у меня» — это и есть commit(), ёпта.

Что происходит, когда ты его вызываешь:

  1. Бармен начинает судорожно пробивать всё, что ты набрал, в кассу (session.flush()). INSERT, UPDATE, DELETE — вся эта SQL-движуха летит в базу.
  2. Кассир (СУБД) говорит: «Окей, принято» и фиксирует операцию (SQL COMMIT).
  3. Транзакция закрывается. Ты рассчитался. Теперь ты можешь либо идти домой, либо начать новый «долг» (новую транзакцию).

Вот типичный сценарий, как это выглядит в коде, если ты не изнеженный Spring-котик, а работаешь с голым Hibernate:

Session session = sessionFactory.openSession();
Transaction transaction = null;
try {
    transaction = session.beginTransaction(); // Начали гулянку, открыли счёт

    // Начинаем набирать в долг
    Employee emp = new Employee("John Doe", "Engineering");
    session.persist(emp); // Записали на листочек

    // ... ещё какие-то операции

    transaction.commit(); // ВСЁ, ПЛАТЁЖ! Сбрасываем всё в БД и закрываем транзакцию.
} catch (Exception e) {
    // Если что-то пошло не так (не хватило денег, карту заблокировали)
    if (transaction != null) {
        transaction.rollback(); // ОТМЕНА! Стираем листочек, всё забываем.
    }
    throw e; // Идём разбираться с проблемой
} finally {
    session.close(); // Выходим из бара. Сессия закрыта.
}

Важные нюансы, блядь:

  • Если ты сидишь на Spring с @Transactional, то этот цирк с commit() и rollback() за тебя делает фреймворк. Ты просто выходишь из метода — и если не было исключений, всё само закоммитится. Красота, да?
  • После commit() сущности-то остаются managed, но транзакция-то закрыта! Это как после расчёта в баре ты остаёшься сидеть за столом. Можешь ещё пить (изменять объекты), но это уже будет новый счёт (новая транзакция), и автоматом ничего не спишется.
  • Если вызвать commit() на транзакции, которая уже не активна (типа ты уже рассчитался или отменил счёт), то получишь исключение. Hibernate тебе так и скажет: «Мужик, да ты уже всё оплатил, на хуя второй раз жмёшь?».

Короче, commit() — это точка невозврата, когда все твои «я потом заплачу» превращаются в реальные изменения в базе. Без него всё твоё крутое ORM — просто болтовня и трата памяти.