I've got a project with Spring Boot (2.3.3.RELEASE), Spring Data JPA (2.3.3.RELEASE) and Hibernate (5.4.20).
I'm trying to recover from DataIntegrityViolationException which happens after trying to save an Entity which violates a database constraint. For example:
@Transactional
public void doSomething() {
// save some data into the database
try {
User user = new User();
user.setName("test");
// This method fails because of a constraint
userService.save(user);
} catch (DataIntegrityViolationException e) {
LOGGER.info("Exception caught. Trying to recover...", e);
}
// continue doing other things
}
As I've caught the exception, when doSomething methods ends I expect that Spring would commit the changes. However, Spring throws the following exception:
org.springframework.transaction.UnexpectedRollbackException: Transaction silently rolled back because it has been marked as rollback-only
As far as I've understood, Hibernate has marked the transaction as rollback-only when the integrity violation has happened and as a result Spring aborts the transaction.
I've tried to avoid this behaviour by adding @Transactional annotation with noRollbackFor attribute in the userService.save method, but it has been useless for this case.
I could create a new transaction for the userService.save method adding @Transactional(propagation = Propagation.REQUIRES_NEW) annotation. However, I want to keep all the changes in the same transaction.
Using plain JDBC there is no problem to recover from a DataIntegrityViolationException and commit the changes after all. ¿Is there any way to change this behaviour with Hibernate?
I've created a demo project in Github to check this behaviour: https://github.com/wearearima/hibernate-rollback