Skip to content

How @Transactional Works Internally, and Rollback Exception Rules

Spring implements @Transactional using Spring AOP and proxy objects.

flowchart LR
    A[Client] --> B[Spring Proxy]
    B --> C[Begin Transaction]
    C --> D[Execute Target Method]
    D --> E{Exception?}
    E -- No --> F[Commit]
    E -- Yes --> G[Rollback]
  • PlatformTransactionManager
  • TransactionInterceptor
  • Spring AOP Proxy

Example:

@Transactional
public void createOrder(Order order) {
orderRepository.save(order);
}

Conceptually:

transactionManager.begin()
method execution
transactionManager.commit()

or rollback on failure.

By default, Spring rolls back transactions only for:

  • RuntimeException
  • Error
Exception Type Rollback
RuntimeException Yes
Checked Exception No

Example:

@Transactional
public void processPayment() {
throw new RuntimeException();
}

To roll back on checked exceptions:

@Transactional(rollbackFor = Exception.class)

or

@Transactional(rollbackFor = SQLException.class)
  • @Transactional works through a Spring AOP proxy: TransactionInterceptor wraps the call, delegating begin/commit/rollback to PlatformTransactionManager.
  • By default, only unchecked exceptions (RuntimeException/Error) trigger a rollback — a checked exception like SQLException will NOT roll back the transaction unless rollbackFor is set explicitly.
  • Since the mechanism is proxy-based, this only applies to calls that pass through the proxy — self-invoked private/internal method calls silently skip transactional behavior.