I have a Spring Boot application in which a service is responsible to create a Business Entity. For simplicity, let's consider:
create(Object toCreate) {
validationService.validate(toCreate);
Object created = repository.save(toCreate);
notificationService.notify(created);
}
Business has changed and now I would like the creation to not fail if notification fails.
I therefore wrapped the notify()
method in a try-catch
block that only logs the error (which is a RuntimeException
).
However when tested, a transaction rollback error was thrown, saying the connection was closed. I do not want any rollback, especially since the NotificationService
does not modify the database.
How can I tell Spring that any exception happening in the NotificationService
is fine and does not require a rollback? I tried annotating the class/method with @Transactional(propagation=NEVER)
but got existing transaction found for transaction marked with propagation 'never'
CodePudding user response:
You can use the option norollbackfor of @Transactional so you have to specify an exception class not the service and when an error occurs in notifications try to throw a specifc error which would not cause a rollback.
CodePudding user response:
Perhaps refactoring your code would help better than the introduction of more complex transaction handling.
Assuming your @Transactional
is on the create()
method, we can see that you have:
- Pre-persistence business logic
- Persistence logic
- Post-persistence business logic
It depends on your use-case, but I would not expect pts. 1 & 3 to contain persistence logic. If that is the case, you could extract your persistence logic in its own service that would itself be a transaction, not the parent.
If you have the need for a transaction in those steps, you could also extract them in their own transaction.
Other leads might be:
- The default rollback behavior is for runtime unchecked exceptions. You could use checked exceptions to avoid the rollback.
- If your notification is separate from persistence and you do not care about the transaction, you could make it an asynchronous call (e.g. with
@Async
). It would be scheduled outside of the transaction in its own context.