SQLException) into unchecked, runtime exceptions (e.g., DataAccessException).
Prevents "exception pollution". You no longer need to declare throws SQLException on all your service and repository interfaces. It keeps method signatures clean and readable.
Decouples your business logic from specific persistence technologies. Whether an error comes from MySQL, MongoDB, or Redis, Spring wraps it in a unified DataAccessException hierarchy.
Infrastructure errors (like missing tables or broken DB connections) are fatal at runtime. Since the application cannot realistically recover from them, forcing repetitive try-catch blocks is useless.
Unchecked exceptions bubble up the call stack naturally. This allows you to catch them in one centralized location using @ControllerAdvice and @ExceptionHandler, returning clean JSON responses.
By default, Spring's @Transactional only rolls back on unchecked exceptions (RuntimeExceptions and Errors). Translating checked database errors into unchecked ones ensures automated and safe transaction rollbacks.
// The interface is tightly coupled to SQL
public interface UserRepository {
User findById(Long id) throws SQLException;
}
// The caller is forced to handle or declare the exception
public class UserService {
public User getUser(Long id) throws SQLException {
return userRepository.findById(id);
}
}
// Clean interface, abstract and uncoupled
public interface UserRepository {
User findById(Long id); // Throws DataAccessException implicitly
}
// Clean caller code
@Service
@Transactional
public class UserService {
public User getUser(Long id) {
// No try-catch or throws declaration needed!
return userRepository.findById(id);
}
}
In enterprise-grade microservices and Identity & Access Management (IAM) APIs, custom domain exceptions should inherit from RuntimeException (unchecked). This prevents checked exception propagation across interfaces, letting a global handler safely intercept the failure and return clean REST responses.
// Custom Unchecked Domain Exception for Authentication
public class InvalidCredentialsException extends RuntimeException {
public InvalidCredentialsException(String msg) {
super(msg);
}
}
// Spring Boot Global Controller Exception Handler for Identity Management
@RestControllerAdvice
public class IdentityExceptionHandler {
@ExceptionHandler(InvalidCredentialsException.class)
public ResponseEntity<ErrorResponse> handleAuthFailure(InvalidCredentialsException ex) {
ErrorResponse response = new ErrorResponse("AUTH_FAILED", ex.getMessage());
return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(response);
}
}
// Simple Error DTO record representation
public record ErrorResponse(String code, String message) {}
@Transactional method?rollbackFor = Exception.class, or rely on Spring's exception translation to convert it into an unchecked exception.org.springframework.dao.DataAccessException, which is a subclass of RuntimeException.PersistenceExceptionTranslator interface, often implemented automatically when using annotations like @Repository.