12

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?

Onkar Saravade
  • 271
  • 1
  • 3
  • 11
  • should only roll back what happens in method1 as the transaction from method2 is closed and therefore every data is persisted – XtremeBaumer Sep 14 '17 at 06:20
  • 3
    Actually no. Both methods are in the same class. So if his code calls method2 using: "this.method2()" then all the Transactional annotations will not matter as the proxy object will not be called at all. And the call has to go through proxy object so that Spring can handle method call with Transactional annotation. – Rafal G. Sep 14 '17 at 06:24

6 Answers6

20

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.

Christian Schneider
  • 19,420
  • 2
  • 39
  • 64
  • 2
    "Also be careful that a method call inside the same object does not trigger the transaction processing" - Does this mean method2 will be part of method1's transaction ? – Rajat Chandak Sep 14 '17 at 06:32
  • 2
    It will be part of the transaction as the transaction is started when method1 start and ended when method1 ends. All calls in between that do not tweak the transaction will take part. So if method2 is annotated or not does not make a difference in this case. – Christian Schneider Sep 14 '17 at 07:40
  • Do we need to add @Transactional to all service level calls in spring boot, does this help optimise DB Connection usage at any level? – Sameer Sep 14 '20 at 21:55
8

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.

Kayaman
  • 72,141
  • 5
  • 83
  • 121
2

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.

0

What happens depends on the chosen transaction propagation. Default is: "REQUIRED" which means that if no transaction exists it will be started.

So in your code method2 will join existing transaction created for method1.

As for your case with both methods in the same class, be careful as this will not work as you expect because of the way Spring proxy objects work.

Rafal G.
  • 4,252
  • 1
  • 25
  • 41
0

It depends on your transaction propagation config.

Related official doc is here

https://docs.spring.io/spring/docs/current/spring-framework-reference/html/transaction.html#tx-propagation

Just note the graph, propagation define a transaction's "transaction context".

toien
  • 288
  • 3
  • 11
0

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