Перейти к основному содержимому

Ошибка TransactionRequiredException

· 2 мин. чтения

1. Обзор

В этом руководстве мы рассмотрим причину ошибки TransactionRequiredException и способы ее устранения.

2. Исключение TransactionRequiredException

Эта ошибка обычно возникает, когда мы пытаемся выполнить операцию с базой данных, которая изменяет базу данных без транзакции .

Например, попытка обновить запись без транзакции:

Query updateQuery
= session.createQuery("UPDATE Post p SET p.title = ?1, p.body = ?2 WHERE p.id = ?3");
updateQuery.setParameter(1, title);
updateQuery.setParameter(2, body);
updateQuery.setParameter(3, id);
updateQuery.executeUpdate();

Вызовет исключение с сообщением следующего содержания:

...
javax.persistence.TransactionRequiredException: Executing an update/delete query
at org.hibernate.query.internal.AbstractProducedQuery.executeUpdate(AbstractProducedQuery.java:1586)
...

3. Предоставление транзакции

Очевидное решение — обернуть любую операцию по изменению базы данных транзакцией:

Transaction txn = session.beginTransaction();
Query updateQuery
= session.createQuery("UPDATE Post p SET p.title = ?1, p.body = ?2 WHERE p.id = ?3");
updateQuery.setParameter(1, title);
updateQuery.setParameter(2, body);
updateQuery.setParameter(3, id);
updateQuery.executeUpdate();
txn.commit();

В приведенном выше фрагменте кода мы вручную инициируем и фиксируем транзакцию. Хотя в среде Spring Boot мы можем добиться этого, используя аннотацию @Transactional .

4. Поддержка транзакций весной

Если нам нужен более детальный контроль, мы можем использовать TransactionTemplate Spring . Потому что это позволяет программисту запускать персистентность объекта непосредственно перед тем, как приступить к выполнению кода метода.

Например, предположим, что мы хотим обновить сообщение перед отправкой уведомления по электронной почте:

public void update() {
entityManager.createQuery("UPDATE Post p SET p.title = ?2, p.body = ?3 WHERE p.id = ?1")
// parameters
.executeUpdate();
sendEmail();
}

Применение @Transactional к описанному выше методу может привести к отправке электронного письма, несмотря на исключение в процессе обновления. Это связано с тем, что транзакция будет зафиксирована только тогда, когда метод завершает работу и собирается вернуться к вызывающей стороне.

Таким образом, обновление сообщения в TransactionTemplate предотвратит этот сценарий, поскольку операция будет немедленно зафиксирована:

public void update() {
transactionTemplate.execute(transactionStatus -> {
entityManager.createQuery("UPDATE Post p SET p.title = ?2, p.body = ?3 WHERE p.id = ?1")
// parameters
.executeUpdate();
transactionStatus.flush();
return null;
});
sendEmail();
}

5. Вывод

В заключение, как правило, рекомендуется заключать операции базы данных в транзакцию. Это помогает предотвратить повреждение данных. Полный исходный код доступен на Github .