Грешка в TransactionRequiredException

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. Поддръжка на транзакции през пролетта

Ако искаме по-фин контрол, можем да използваме Spring's TransactionTemplate . Тъй като това позволява на програмиста да задейства постоянството на обект непосредствено преди да продължи с кодовото изпълнение на метод.

Да приемем например, че искаме да актуализираме публикацията, преди да изпратим известие по имейл:

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.