Spring事务:@Transactional回滚配置选Exception还是RuntimeException?
rollbackFor = Exception.class and Default RuntimeException Behavior Great question! Let’s break this down clearly based on how Spring handles transaction rollbacks—this is a super common point of confusion for developers working with Spring transactions.
First, Understand Spring's Default Rule
By default, Spring’s @Transactional annotation only triggers a transaction rollback for:
- Unchecked exceptions:
RuntimeExceptionand all its subclasses (likeNullPointerException,IllegalArgumentException) - Errors: Serious system-level issues like
OutOfMemoryError
It does NOT automatically roll back for checked exceptions (classes that extend Exception directly, not RuntimeException—think custom business exceptions you define as checked exceptions).
When to Use Which Configuration
1. Go with @Transactional(rollbackFor = Exception.class)
Use this when you want every exception (checked AND unchecked) to trigger a rollback. This is necessary if:
- Your code throws custom checked exceptions (e.g.,
public class BadRequestException extends Exception) - You need those checked exceptions to undo any database changes made earlier in the transaction
For example, if you have a method that saves an order first, then throws a checked exception when validation fails—without rollbackFor = Exception.class, the saved order would stay in the database, which is almost never what you want.
2. Stick with Default @Transactional (No rollbackFor Setting)
Use this default behavior when you only want unchecked exceptions/Errors to trigger rollbacks. This works great if:
- All your custom business exceptions extend
RuntimeException(e.g.,public class BadRequestException extends RuntimeException) - You treat checked exceptions as "expected" business outcomes that don’t require undoing database changes (though this is less common in practice)
Spring’s default rule will automatically roll back the transaction whenever an unchecked exception is thrown, so no extra configuration is needed here.
Code Examples to Illustrate
Example 1: Checked Exception + rollbackFor = Exception.class
// Custom checked exception public class BadRequestException extends Exception { public BadRequestException(String message) { super(message); } } @Service public class OrderService { @Transactional(rollbackFor = Exception.class) public void createOrder(OrderDto orderDto) throws BadRequestException { // Step 1: Save order to database orderRepository.save(orderDto); // Validation fails—throw checked exception if (orderDto.getAmount() <= 0) { throw new BadRequestException("Order amount cannot be negative"); } // Step 2: Deduct stock (never runs if exception is thrown) stockRepository.decreaseStock(orderDto.getProductId(), orderDto.getQuantity()); } }
Without
rollbackFor = Exception.class, the saved order would remain in the database even after the exception is thrown. Adding this setting ensures the transaction rolls back entirely.
Example 2: Unchecked Exception + Default @Transactional
// Custom unchecked exception public class BadRequestException extends RuntimeException { public BadRequestException(String message) { super(message); } } @Service public class OrderService { @Transactional // No extra config needed public void createOrder(OrderDto orderDto) { // Step 1: Save order to database orderRepository.save(orderDto); // Validation fails—throw unchecked exception if (orderDto.getAmount() <= 0) { throw new BadRequestException("Order amount cannot be negative"); } // Step 2: Deduct stock (never runs if exception is thrown) stockRepository.decreaseStock(orderDto.getProductId(), orderDto.getQuantity()); } }
Here, Spring automatically rolls back the transaction when
BadRequestExceptionis thrown, since it’s a subclass ofRuntimeException. The saved order is removed from the database as expected.
Key Takeaway
- Choose
@Transactional(rollbackFor = Exception.class)if you need all exceptions (checked and unchecked) to trigger rollbacks, especially when working with custom checked exceptions. - Use the default
@Transactionalif your custom exceptions are unchecked (extendRuntimeException) or you only want system/unexpected exceptions to roll back transactions.
内容的提问来源于stack exchange,提问作者k.sh

