Spring реализует прекрасную поддержку декларативного управления транзакциями. В сущности всё управление сводится к корректной расстановке аннотации @Transactional, а всё остальное берёт на себя Spring. Но, в случае необходимости, можно взять контроль в свои руки и вернуть управление транзакциями в код.
Этот пример основан на статье Декларативное управление транзакциями в Spring и далее приведены только изменения в оригинальном коде.
Ручное управление транзакциями начинается с объекта TransactionTemplate, который конфигурируется PlatformTransactionManager:
1 2 3 4 | @Bean public TransactionTemplate transactionTemplate() { return new TransactionTemplate(transactionManager()); } |
TransactionTemplate использует парадигму callback (обратных вызовов) для исполнения кода внутри транзакции. В метод execute() передаётся код для исполнения, который будет синхронно исполнен в контексте транзакции.
1 2 3 4 5 6 7 8 9 10 | @Override public final void addGreet(final Greeter g) { transactionTemplate.execute(new TransactionCallbackWithoutResult() { @Override protected void doInTransactionWithoutResult(TransactionStatus transactionStatus) { em.persist(g); } }); } |
В callback передаётся объект TransactionStatus, представляющий собой обёртку вокруг реальной транзакции. С его помощью можно управлять транзакцией, например программно откатывать её.
1 2 3 4 5 6 7 8 9 10 11 12 | @Override public final void updateGreet(final Greeter g, final String newTarget) { transactionTemplate.execute(new TransactionCallbackWithoutResult() { @Override protected void doInTransactionWithoutResult(TransactionStatus status) { Greeter greet = em.merge(g); greet.setTarget(newTarget); status.setRollbackOnly(); } }); } |
TransactionTemplate поддерживает все те же возможности, что и аннотация @Transactional, которые настраиваются вызовами соответствующих методов:
1 2 3 4 5 6 7 | @Override public final List<Greeter> getGreetings() { TransactionTemplate tx = new TransactionTemplate(transactionManager); tx.setReadOnly(true); return tx.execute(status -> em.createQuery("from Greeter", Greeter.class) .getResultList()); } |
Код примера доступен на github