Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Call @Transactional annotated method from another @Transactional annotated method

What happens when I call one transactional method from another transactional method, now my second transactional method completed, and it came back in 1st transactional method, and unfortunately it fail, so will it roll back everything, means will it roll back 2nd transactional method changes..?? Note: both method are in same class

@Transactional 
public void method1(){
   //do something
   call method2();
  //do something
  ...
  ...
  failed here
}

@Transactional
public void method2(){
  //do something
  save()
}

So in above example will it rollback whatever I saved in 2nd transactional method?

like image 754
Onkar Saravade Avatar asked Sep 14 '17 06:09

Onkar Saravade


People also ask

What happens if one @transactional annotated method is calling another @transactional annotated method inside a same object instance?

1 Answer. Show activity on this post. If you call method2() from method1() within the same class, the @Transactional annotation of the second method will not have any effect because it is not called through proxy, but directly.

What happens if a method annotated with @transactional calls another method annotated with @transactional?

If you call a method with a @Transactional annotation from a method with @Transactional belonging to the same Spring Bean , then the called methods transactional behavior will not have any impact on the transaction.

What happens if a method annotated with @transactional?

The @Transactional annotation makes use of the attributes rollbackFor or rollbackForClassName to rollback the transactions, and the attributes noRollbackFor or noRollbackForClassName to avoid rollback on listed exceptions. The default rollback behavior in the declarative approach will rollback on runtime exceptions.

Can @transactional annotation only be used at class level?

The @Transactional annotation on the class level will be applied to every method in the class. However, when a method is annotated with @Transactional (like, updateFoo(Foo foo) ) this will take precedence over the transactional settings defined at the class level.


4 Answers

It depends on the txType. By default it is REQUIRED. So the first method starts the transaction and the same transaction is used for the call to method2.

Also be careful that a method call inside the same object does not trigger the transaction processing. As typically the transaction handling is handled as proxy that only works when calling an injected other bean. In your example you would not notice a difference though.

A case where this would matter is if method1 is not @Transactional and method2 is. In this case there would be no transaction at all.

like image 160
Christian Schneider Avatar answered Nov 15 '22 19:11

Christian Schneider


If both methods are in the same class, the @Transactional annotation won't even be considered when calling from another method of the same class. It doesn't matter what you put there, or even if you leave it out. There still will be a transaction started by method1(), but then you're stuck in that transaction.

If the second method were in a separate class, you could use Propagation.REQUIRES_NEW to have it run in its own transaction, meaning that even if method1() later on failed, any changes in method2() would still have made.

The default transaction propagation of REQUIRED starts a new transaction if none exist, or joins an existing transaction. Again, in the separate class situation it results in the rollback of any changes made in method2() when method1() fails.

like image 39
Kayaman Avatar answered Nov 15 '22 20:11

Kayaman


Spring boot provides concept of propagation with @Transactions. Propagation level decides that inner transaction should be part of same outer transaction or it should be different isolated one. By default propagation level is REQUIRED which means inner transaction will be part of same outer transaction, so if inner transaction fails whole transaction will get rollback.

Now its important to know that Rollback works for only Runtime exceptions by default. For checked Exceptions you have to specify that explicitly @Transcations(rollbackFor = Exception.class)

So to answer for your question is YES! It does rollback changes made by inner transaction.

like image 41
Rajat Chandak Avatar answered Nov 15 '22 18:11

Rajat Chandak


this is a typical question:

  1. You should call method2() by self injected object or use this notation, because another ways will call method2 and avoid call proxy object method, which contain all transactional logic.

    In proxy mode (which is the default), only external method calls coming in through the proxy are intercepted. This means that self-invocation, in effect, a method within the target object calling another method of the target object, will not lead to an actual transaction at runtime even if the invoked method is marked with @Transactional. Also, the proxy must be fully initialized to provide the expected behaviour so you should not rely on this feature in your initialization code, i.e. @PostConstruct

  2. Nested Transaction behaviour depends on @Transactional parameters. For example - Use PROPAGATION_REQUIRES_NEW for create new transaction for nested methods with @Transactional. See more info in official doc
like image 42
Kirill Tolkachev Avatar answered Nov 15 '22 20:11

Kirill Tolkachev