TransactionTemplate — programmatic transactions, when to… — Cracked Java
// Spring Framework & Spring Boot · Transactions Deep Dive
SeniorCoding

TransactionTemplate — programmatic transactions, when to use it.

TransactionTemplate is the programmatic alternative to @Transactional: instead of an annotation and a proxy, you wrap a block of code in a callback and the template runs it inside a transaction. Same PlatformTransactionManager underneath — you're just driving it by hand.

How it looks

@Service
class ImportService {

    private final TransactionTemplate tx;
    private final ImportRepository repo;

    ImportService(PlatformTransactionManager txManager, ImportRepository repo) {
        this.tx = new TransactionTemplate(txManager);
        this.repo = repo;
    }

    public ImportResult run(Batch batch) {
        return tx.execute(status -> {          // begins a transaction
            repo.save(batch.header());
            if (batch.isEmpty()) {
                status.setRollbackOnly();      // explicit rollback, no exception needed
                return ImportResult.empty();
            }
            repo.saveAll(batch.lines());
            return ImportResult.ok();          // returning commits
        });
    }
}

execute returns your value; executeWithoutResult takes a Consumer<TransactionStatus> for void work. You set propagation, isolation, timeout, and read-only on the template instance. Crucially, any exception that escapes the callback triggers a rollback — including checked exceptions (wrap them or use execute's lambda which only allows unchecked), unlike the annotation's checked-commits default.

When to reach for it

  • Self-invocation. Because there's no proxy, calling it from within the same bean just works — a clean escape from that trap.
  • Fine-grained boundaries. You want a transaction around only part of a method, or multiple short transactions in a loop, rather than one annotation spanning the whole method.
  • Conditional rollback without throwing — status.setRollbackOnly() reads more naturally than manufacturing an exception.
  • Dynamic settings chosen at runtime (propagation/timeout computed from inputs), which annotations can't express.
  • Programmatic / non-bean contexts where there's no proxied method to annotate.

Mark your status