rollbackFor vs noRollbackFor. Default rollback rule (only… — Cracked Java
// Spring Framework & Spring Boot · Transactions Deep Dive
MidTheoryTrick

rollbackFor vs noRollbackFor. Default rollback rule (only unchecked exceptions).

The default rollback rule trips almost everyone: Spring rolls back only on RuntimeException (unchecked) and Error — a checked exception commits the transaction. This is a deliberate inheritance from EJB semantics, and it's the source of the classic "my method threw but the data was still saved" bug.

The default rule

When the proxied method throws, the TransactionInterceptor checks the exception type:

  • RuntimeException or Errorroll back.
  • any checked Exception (a java.lang.Exception that isn't a RuntimeException) → commit.
@Transactional
public void process(Order o) throws IOException {
    repo.save(o);
    sendFile(o);                 // throws IOException (checked)
    // -> the save above is COMMITTED, because checked exceptions don't roll back
}

That silent commit on a checked exception is the trap. If you want the save undone, you must override the rule.

Overriding it

rollbackFor adds exception types that should roll back (typically a checked one):

@Transactional(rollbackFor = IOException.class)
public void process(Order o) throws IOException { ... }   // now rolls back

noRollbackFor does the opposite — names exceptions that should not roll back even though they normally would (e.g. a RuntimeException you treat as a benign, expected signal):

@Transactional(noRollbackFor = OptimisticLockRetryHint.class)
public void apply() { ... }   // this runtime exception commits anyway

Both accept arrays, and matching is by assignability (subclasses included). When multiple rules match, the most specific (closest in the type hierarchy) wins.

Mark your status