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