0

I have a API , That looks like below

@Transaction
void method (){
try{
  service1.insertOne();
  service2.insertTwo();
}
catch(Exception ex) {
// log exception
}
}

In Service classes, I am checking for certain validation and I am throwing an exception which is a subclass of RuntimeException. When i throw this exception, javax.persistence.RollbackException: Transaction marked as rollbackOnly . While it is preventing the data in the first service from not being inserted , since the second service validation has failed, I am not quite quite sure if this is the right way to handle this scenario.

In case if the Exception is not a sub-class of Exception, even when the validation for service2 fails , data in service1 gets inserted, but i do see the custom exception being thrown. So i am not sure where i am going wrong. Any help is appreciated.

Sam
  • 1,298
  • 6
  • 30
  • 65

4 Answers4

0

the Spring Framework’s transaction infrastructure code only marks a transaction for rollback in the case of runtime, unchecked exceptions; that is, when the thrown exception is an instance or subclass of RuntimeException.

https://docs.spring.io/spring/docs/current/spring-framework-reference/data-access.html#transaction-declarative-rolling-back

So, it must stay as a type of RuntimeException.

Probably you have Transactional annotation on top of service1.insertOne and/or service2.insertTwo() methods and that's why you get javax.persistence.RollbackException: Transaction marked as rollbackOnly.

You don't need those additional annotations (if they're exist) since there is an already active transaction.

Check this answer out.

sedooe
  • 3,100
  • 2
  • 22
  • 27
0

If your insertOne, and insertTwo methods are marked as @Transactional, default propagation is Required. So you should see all that executed in one transaction. Link to docs

In second case it works as it should as well. If you throw custom transaction, then Spring does not take case of it. You can update that default behavior, by providing rollbackFor. In that case you will expect almost the same situation as in first case.

So it is more question to you - do you want your validation to mark transaction as rollbackOnly, or not. I would say yes.

Perhaps question is too abstract. Let's say you are putting invoice, and positions - then I would expect this transaction to be rolled back. However, if you add group, and users... Group can go, since problem is with user.

Michał Zaborowski
  • 3,911
  • 2
  • 19
  • 39
0

Just use the noRollbackForoption of the @Transactional to specify for which exception should not trigger a rollback: https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/transaction/annotation/Transactional.html#noRollbackFor--

@Transaction (noRollbackFor=YourRuntimeException.class)
void method (){
    try{
      service1.insertOne();
      service2.insertTwo();
    }
    catch(Exception ex) {
    // log exception
    }
}
Tom Van Rossom
  • 1,440
  • 10
  • 18
0

I am not quite quite sure if this is the right way to handle this scenario.

YES this way is fine, When you marked your method void method () as Transactional , you instructed whenever there is a runtime exception, please rollback . When a code block with in the @Transactional annotated method observes a runtimeexception during execution, the Spring framework will keep it is as flag ('rollbackOnly') under ThreadLocal variable. Please note that after completion of method() , spring will commit if it finds that the flag ('rollbackOnly') is false. Otherwise spring will instruct the transaction manager to rollback all of the inserts.

even when the validation for service2 fails , data in service1 gets inserted, but i do see the custom exception being thrown. So i am not sure where i am going wrong

As explained above.

Amit Parashar
  • 1,447
  • 12
  • 15