Ручное управление транзакциями JPA vs. декларативный @Transactional
Замените многословные блоки begin/commit/rollback одной аннотацией @Transactional.
Сравнение кода
✕ Java EE
@PersistenceContext
EntityManager em;
public void transferFunds(Long from, Long to,
BigDecimal amount) {
EntityTransaction tx = em.getTransaction();
tx.begin();
try {
Account src = em.find(Account.class, from);
Account dst = em.find(Account.class, to);
src.debit(amount);
dst.credit(amount);
tx.commit();
} catch (Exception e) {
tx.rollback();
throw e;
}
}
✓ Jakarta EE 8+
@ApplicationScoped
public class AccountService {
@PersistenceContext
EntityManager em;
@Transactional
public void transferFunds(Long from, Long to,
BigDecimal amount) {
var src = em.find(Account.class, from);
var dst = em.find(Account.class, to);
src.debit(amount);
dst.credit(amount);
}
}
Заметили проблему в этом коде? Сообщите нам.
Почему современный подход лучше
Никакого шаблонного кода
Одна аннотация заменяет повторяющиеся блоки begin/commit/rollback с try-catch.
Более безопасный откат
Контейнер гарантирует откат при непроверяемых исключениях — никакого риска забыть блок catch.
Декларативное управление
Распространение, изоляция и правила отката выражаются как атрибуты аннотации.
Старый подход
Ручная транзакция
Современный подход
@Transactional
Начиная с JDK
11
Сложность
Средний
Поддержка JDK
Ручное управление транзакциями JPA vs. декларативный @Transactional
Доступно
Широко доступно начиная с Jakarta EE 8 / Java 11
Как это работает
Ручное управление транзакциями требует явных вызовов begin(), commit() и rollback(), обёрнутых в блоки try-catch — каждый сервисный метод повторяет этот шаблонный код. Аннотация @Transactional делегирует управление жизненным циклом контейнеру — он запускает транзакцию перед вызовом метода, фиксирует её при успехе и автоматически откатывает при RuntimeException.
Связанная документация
Доказательство