1. Знайомство з транзакціями в Hibernate
До всього, що ми вже розібрали, хотілося б ще додати інформацію про транзакції. Як ти вже знаєш, транзакція — це група дій, які мають бути виконані лише всі разом. Якщо будь-яка дія не виконалася або виконалася з помилкою, всі інші дії повинні бути скасовані.
Hibernate вміє працювати з двома видами транзакцій:
- JDBC
- JTA
JDBC-транзакція — це фактично транзакція бази даних. Вона прив'язана до роботи з базою даних, JDBC-з'єднання. І слідкує за тим, щоб дії під час роботи з базою даних виконувались як слід: або всі чи нічого.
JTA-транзакція — це транзакція рівня програми. Вона не прив'язана до жодної бази даних. Її завдання — слідкувати, щоб деякі дії виконувались: всі, або жодна.
Наприклад, ти можеш записувати дані до кількох різних баз даних у межах однієї JTA-транзакції. Тоді, якщо відбудеться помилка, JTA-транзакція повинна буде відкотити зміни у всіх базах даних. Навіть ті, які були успішно виконані з точки зору конкретної бази даних.
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 не станеться помилка. Помилки завжди відбуваються. Тобі потрібно просто прийняти цей факт і бути готовим до нього.
3. Transaction Manager
З точки зору менеджменту транзакцій, Hibernate — це просто полегшена оболонка об'єктів для JDBC. Сам Hibernate немає функцій обробки транзакцій. Hibernate Transaction є оболонкою для базової транзакції JDBC (або оболонки транзакцій JTA). JDBCTransaction використовується за замовчуванням. Приклад із файлу налаштувань Hibernate:
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-код |
---|---|
|
|
Отже рідні транзакції Hibernate — це просто рідні JDBC-дзвінки до бази даних. Не більше і не менше. А ось JTA транзакції — це вже цікавіше. Але про це іншим разом.
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ