Transactionsmedium3-5 years

A `@Transactional` transfer debits one account and then throws a checked `InsufficientFundsException` from a later check. The caller catches it, and the money has moved anyway. Why did the transaction commit, and how do you make it roll back?

By default Spring rolls back only on unchecked exceptions (RuntimeException and Error). A checked exception is treated as a declared business outcome, so the proxy commits on the way out, and the debit that dirty checking noticed is written, even though the caller saw an exception. The fix is to say what you mean: @Transactional(rollbackFor = InsufficientFundsException.class) (or rollbackFor = Exception.class), or prefer unchecked exceptions for failures in a transactional service so you never meet this default.

The lesson behind it →
More on Transactions