Транзакции

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

4.1 Знакомство с транзакциями в Hibernate

Ко всему вышесказанному хотелось бы еще добавить информацию про транзакции. Как ты уже знаешь, транзакция – это группа действий, которые должны быть выполнены только все вместе. Если какое-либо действие не выполнилось или выполнилось с ошибкой, то все остальные действия должны быть отменены.

Hibernate умеет работать с двумя видами транзакций:

  • JDBC
  • JTA

JDBC-транзакция, – это фактически транзакция базы данных. Она привязана к работе с базой данных, к JDBC-соединению. И следит за тем, чтобы действия при работе с базой данных выполнялись как надо: или все или ничего.

JTA – транзакция – это транзакция уровня приложения. Она не привязана ни к какой базе данных. Ее задача следить, чтобы некоторые действия выполнялись: или все, или ничего.

Например, ты можешь записывать данные в несколько разных баз данных в рамках одной JTA-транзакции. Тогда если произойдет ошибка, то JTA-транзакция должна будет откатить изменения во всех базах данных. Даже те, которые были выполнены успешно с точки зрения конкретной базы данных.

4.2 Hibernate Transactions Interface

В библиотеке Hibernate транзакция представлена интерфейсом Transaction, который может иметь различные реализации. Например, при работе со Spring, Spring предоставляет свой собственный механизм JTA-транзакций.

Методы этого интерфейса такие:

# Метод Описание
1 begin() Стартует новую транзакцию
2 commit() Заканчивает транзакцию, пушит/комитит все изменения
3 rollback() Откатывает текущую транзакцию
4 setTimeout(int seconds) Устанавливает максимальное время выполнения транзакции
5 isActive() Проверяет активная транзакция или нет
6 wasRolledBack() Проверяет нормально ли откатилась транзакция
7 wasCommitted() Проверяет нормально ли транзакция закомитилась
8 registerSynchronization() Регистрирует callback для контроля транзакции

Важно! Создание объекта транзакции и запуск транзакции – это разные вещи. Тут можно провести аналогию с классом Thread. Когда ты создаешь объект Thread(), то новый поток JVM еще не запускает. Чтобы его запустить, нужно вызвать метод start() у объекта Thread. То же самое и с транзакцией – ей нужно вызвать метод begin().

Пример того, как обычно работают с транзакциями в Hibernate:


Session session = sessionFactory.openSession();
Transaction transaction = session.getTransaction();
try {
    transaction.begin();
    Long count = session.createQuery("select count(*) from Employee", Long.class).uniqueResult();
    transaction.commit();
}
catch (Exception e) {
	if (transaction.getStatus() == ACTIVE || transaction.getStatus() == MARKED_ROLLBACK) {
    transaction.rollback();
    }
}
finally {
	session.close();
	sessionFactory.close();
}

Мы тут видим три вещи:

Во-первых, вся работа с базой оборачивается в транзакцию с помощью вызова методов begin() и commit() Все действия между вызовами этих двух методов должны быть выполнены: или все вместе, или ничего.

Во-вторых, если произошла любая ошибка мы пробуем откатить транзакцию – вызвать метод rollback(). Это значит, что TransactionManger должен сначала записывать все действия, которые были между begin() и commit(), а затем вернуть все как было, если мы вызвали rollback().

И кстати, не факт, что при вызове метода rollback не произойдет ошибки. Ошибки всегда происходят. Тебе нужно просто принять этот факт и быть к нему готовым.

4.3 Transaction Manager

С точки зрения менеджмента транзакций, Hibernate – это просто облегченная оболочка объектов для JDBC. Сам Hibernate не имеет функций обработки транзакций. Hibernate Transaction на самом деле является оболочкой для базовой транзакции JDBC (или оболочки транзакций JTA). JDBCTransaction используется по умолчанию. Пример из файла настроек HIberante:


hibernate.transaction.factory_class  org.hibernate.transaction.JTATransactionFactory
hibernate.transaction.factory_class org.hibernate.transaction.JDBCTransactionFactory

Давай еще раз посмотрим на наш код с использованием транзакций:


Session session = sessionFactory.openSession();
Transaction transaction = session.getTransaction();
transaction.begin();
//тут ваш код по работе с базой
session.flush();
transaction.commit();
session.close();

А теперь давай посмотрим на код класса JDBCTransaction:


public class JDBCTransaction implements Transaction {
 
    public void begin() throws HibernateException {
    	...
    	if (toggleAutoCommit) jdbcContext.connection().setAutoCommit(false);
    	...
    }
}

Это метод для запуска транзакции. Затем посмотреть на метод отправки:


public void commit() throws HibernateException {
    ...
    jdbcContext.connection().commit();
    ...
    jdbcContext.connection().setAutoCommit( true );
    ...
}

Теперь давай подставим этот код в код примера с Hibernate:

Hibernate Простой JDBC-код

Session session = sessionFactory.openSession();
Transaction transaction = session.getTransaction();
transaction.begin();
//тут твой код по работе с базой
session.flush();
transaction.commit();
session.close();

Connection conn = jdbcContext.connection();
conn.setAutoCommit(false);
 
//тут твой код по работе с базой
conn.commit ()
conn.setAutoCommit(true);
conn.close();

Так что родные транзакции Hibernate – это просто родные JDBC-вызовы к базе данных. Ни больше и ни меньше. А вот JTA транзакции – это уже поинтереснее. Но об этом в другой раз.

1
Задача
Модуль 4. Работа с БД, 16 уровень, 3 лекция
Недоступна
Транзакции
Транзакции
Комментарии (4)
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ
Эльдар Агзамов Уровень 112
22 ноября 2025
Здесь есть ошибка, соединение hibernate берет из hikariCP только в момент обращения к БД, то есть в примере выше в момент session.flush(); сбрасывает persistence context на диск, делает сессию чистой, и в момент session.close(); сессия не закрывается как ресурс как показано session.close(); а кладется connection pool.
Павел Уровень 19 Expert
5 апреля 2024
Посмотрел, для того чтобы использовать JTA недостаточно добавить строку настройки в файл конфигурации. Увидел совет: "Настройте ваше приложение для использования JTA. Это может потребовать настройки в вашем контейнере приложений (например, WildFly, Tomcat с поддержкой JTA) или использование JTA-компонента (например, Atomikos)." Возможно и это еще не все.
Mitrus Latovous Уровень 41
1 декабря 2023
А про блокировки материала в этом курсе нет?
Эдуард Уровень 1 Expert
14 декабря 2022
В задаче пока не реализовал toString в обоих классах, задача не проходила.