I created a service method that creates user accounts. If creation fails because the given e-mail-address is already in our database, I want to send the user an e-mail saying they are already registered:
@Transactional(noRollbackFor=DuplicateEmailException.class)
void registerUser(User user) {
try {
userRepository.create(user);
catch(DuplicateEmailException e) {
User registeredUser = userRepository.findByEmail(user.getEmail());
mailService.sendAlreadyRegisteredEmail(registeredUser);
}
}
This does not work. Although I marked the DuplicateEmailExcepetion
as "no rollback", the second SQL query (findByEmail) still fails because the transaction was aborted.
What am I doing wrong?
There is no @Transactional
annotation on the repository.
Note however that the Spring Framework's transaction infrastructure code will, by default, only mark a transaction for rollback in the case of runtime, unchecked exceptions; that is, when the thrown exception is an instance or subclass of RuntimeException. (Errors will also - by default - result in a rollback.)
Spring Boot implicitly creates a proxy for the transaction annotated methods. So for such methods the proxy acts like a wrapper which takes care of creating a transaction at the beginning of the method call and committing the transaction after the method is executed.
@Transactional can only rollback exceptions thrown by subclasses of RuntimeException and RuntimeException, and cannot rollback Exception exceptions. It is recommended that everyone use @Transactional(rollbackFor = Exception.class) scenarios. If you need to support rollback Exception.
That's not a problem with Spring / JDBC or your code, the problem is with the underlying database. For example, when you are using the Postgres if any statement fails in a transaction all the subsequent statements will fail with current transaction is aborted
.
For example executing the following statements on your Postgres:
> start a transaction
> DROP SEQUENCE BLA_BLA_BLA;
> Error while executing the query; ERROR: sequence "BLA_BLA_BLA" does not exist"
> SELECT * FROM USERS;
> ERROR: current transaction is aborted, commands ignored until end of transaction block
Still the SELECT and subsequent statements are expected to succeed against MySQL, Oracle and SQL Server
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With