When you use the <repositories> element in XML or @EnableJpaRepositories in Java config:
🔁 It automatically applies exception translation to any bean annotated with
@Repository.
JPA throws provider-specific exceptions (e.g., javax.persistence.PersistenceException), which are not consistent across different providers (like Hibernate, EclipseLink, etc.).
Spring wraps those into a consistent hierarchy:
➡️ org.springframework.dao.DataAccessException and its subclasses.
So regardless of whether you use Hibernate or another JPA provider, you always catch Spring exceptions like:
DataIntegrityViolationExceptionEmptyResultDataAccessExceptionOptimisticLockingFailureException
Behind the scenes, Spring uses a proxy (AOP) to intercept calls to your @Repository methods and translate any caught exception into one of Spring’s standard exceptions.
Example:
@Repository
public interface UserRepository extends JpaRepository<User, Long> {
}If save() throws a javax.persistence.EntityExistsException, Spring will catch it and rethrow it as a DataIntegrityViolationException.
You get cleaner, portable, and consistent error handling without having to write vendor-specific code.
You try to insert a record with a duplicate primary key, which causes a database integrity violation.
@Entity
public class User {
@Id
private Long id;
private String email;
// getters and setters
}@Repository
public interface UserRepository extends JpaRepository<User, Long> {
}@Service
public class UserService {
@Autowired
private UserRepository userRepository;
public void insertDuplicateUser() {
User user1 = new User();
user1.setId(1L);
user1.setEmail("a@example.com");
User user2 = new User();
user2.setId(1L); // Duplicate ID
user2.setEmail("b@example.com");
userRepository.save(user1);
userRepository.save(user2); // This will throw exception
}
}@RestController
public class UserController {
@Autowired
private UserService userService;
@GetMapping("/test")
public String test() {
try {
userService.insertDuplicateUser();
} catch (DataAccessException e) {
return "Spring translated exception: " + e.getClass().getSimpleName();
}
return "Success";
}
}- JPA throws a
javax.persistence.PersistenceException(or more specifically,EntityExistsExceptionor a SQL exception). - Because the repository is annotated with
@Repository, and@EnableJpaRepositoriesis active, - Spring catches the JPA exception and wraps it into
DataIntegrityViolationException(a subclass ofDataAccessException). - You can now handle it in a consistent, Spring-style way — independent of your JPA provider.