Transactions Deep Dive — Java Interview Guide | Cracked Java
Mid

Transactions Deep Dive

What @Transactional does and where to put it, propagation and isolation, the default rollback rule, the AOP-proxy implementation, the self-invocation trap, and TransactionTemplate.

Prereqs: spring-data-jpa

Spring transactions are declarative — you annotate a method with @Transactional and an AOP proxy wraps it in begin/commit/rollback — but everything that surprises people in production comes from understanding that the magic is just a proxy around your bean. Strip away the annotation and the model is simple: a PlatformTransactionManager (e.g. DataSourceTransactionManager for JDBC, JpaTransactionManager for Hibernate) opens a transaction, binds the connection to the current thread via a ThreadLocal, and commits or rolls back when your method returns or throws.

The proxy intercepts the call, asks the transaction manager for a transaction according to the propagation rule, runs your code, and then decides commit vs rollback from the rollback rules. That's the whole lifecycle.

@Service
class OrderService {

    private final OrderRepository orders;
    OrderService(OrderRepository orders) { this.orders = orders; }

    @Transactional                       // join-or-create (REQUIRED), commit on return
    public Order place(NewOrder cmd) {
        Order o = orders.save(Order.from(cmd));
        charge(o);                        // throws RuntimeException -> whole tx rolls back
        return o;
    }
}

Three things decide behavior on every annotated call. Propagation — does this method join the caller's transaction, suspend it and start a fresh one, or demand one already exist? Isolation — which concurrency anomalies the database is allowed to show, mapped onto the DB's own levels (Postgres defaults to READ_COMMITTED). Rollback rules — by default Spring rolls back only on RuntimeException and Error; a checked exception commits unless you say rollbackFor.

The traps are equally consistent. Put @Transactional on a public service method, not on a private method or a controller. Beware self-invocation: this.other() calls the raw bean and bypasses the proxy entirely, so the annotation is silently ignored. And readOnly = true is a real optimization, not a no-op.

The questions below dissect what the annotation actually does, all seven propagation levels, isolation mapped to Postgres, the rollback rules, the AOP internals, the self-invocation trap, TransactionTemplate, read-only transactions, and multi-datasource transactions.

Questions

9 in this topic