I'm using Spring and Hibernate in one of the applications that I'm working on and I've got a problem with handling of transactions.
I've got a service class that loads some entities from the database, modifies some of their values and then (when everything is valid) commits these changes to the database. If the new values are invalid (which I can only check after setting them) I do not want to persist the changes. To prevent Spring/Hibernate from saving the changes I throw an exception in the method. This however results in the following error:
Could not commit JPA transaction: Transaction marked as rollbackOnly
And this is the service:
@Service class MyService { @Transactional(rollbackFor = MyCustomException.class) public void doSth() throws MyCustomException { //load entities from database //modify some of their values //check if they are valid if(invalid) { //if they arent valid, throw an exception throw new MyCustomException(); } } }
And this is how I invoke it:
class ServiceUser { @Autowired private MyService myService; public void method() { try { myService.doSth(); } catch (MyCustomException e) { // ... } } }
What I'd expect to happen: No changes to the database and no exception visible to the user.
What happens: No changes to the database but the app crashes with:
org.springframework.transaction.TransactionSystemException: Could not commit JPA transaction; nested exception is javax.persistence.RollbackException: Transaction marked as rollbackOnly
It's correctly setting the transaction to rollbackOnly but why is the rollback crashing with an exception?
As a result of an error condition or exception, an application can determine that the current transaction should be rolled back. However, the application should not attempt to rollback the transaction directly.
An object level transaction is one in which a set of changes made to a set of objects are committed to the database as a single unit. JPA provides two mechanisms for transactions. When used in Java EE JPA provides integration with JTA (Java Transaction API).
RollbackException exception is thrown when the transaction has been marked for rollback only or the transaction has been rolled back instead of committed. This is a local exception thrown by methods in the UserTransaction , Transaction , and TransactionManager interfaces.
In a Spring application, the web @Controller calls a @Service method, which is annotated using the @Transactional annotation. By default, Spring transactions are read-write, but you can explicitly configure them to be executed in a read-only context via the read-only attribute of the @Transactional annotation.
My guess is that ServiceUser.method()
is itself transactional. It shouldn't be. Here's the reason why.
Here's what happens when a call is made to your ServiceUser.method()
method:
Now if ServiceUser.method()
is not transactional, here's what happens:
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