Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring @Transactional Annotation : Self Invocation

I know when a transactional method is called from inside the same class it wouldn't be run in a transaction. Spring creates a proxy for transactional methods and wraps them in a try-catch block and rolls back if an exception occurs. Consider the following scenario:

@Transactional
public void saveAB(A a, B b)
{
    saveA(a);
    saveB(b);
}

@Transactional
public void saveA(A a)
{
    dao.saveA(a);
}

@Transactional
public void saveB(B b)
{
    dao.saveB(b);
}

Assume saveAB is called from another object and an exception occurred in saveB, so saveA completed successfully but saveB did not. To my knowledge even though saveA and saveB are not transactional (because they are called from the same object), since saveAB is transactional it should still roll back.

What I don't understand is why do people say self invocation breaks transaction? As long as the caller method is transactional shouldn't everything work as expected? Is there anything I'm missing here?

like image 981
Bahattin Ungormus Avatar asked May 29 '14 10:05

Bahattin Ungormus


People also ask

What is self invocation in Spring?

Self-invocation, as defined in the Spring documentation, is a method within the target object calling another method of the target object. In our current example, we have the method testTransactional1() calling the method testTransactional2() inside of the same target object; thus, we are experiencing self-invocation.

What is the use of @transactional annotation in Spring?

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.

Is it sufficient to annotate the classes with the @transactional annotation?

You can place the @Transactional annotation before an interface definition, a method on an interface, a class definition, or a public method on a class. However, the mere presence of the @Transactional annotation is not enough to activate the transactional behavior.

Does @transactional work on private methods?

The answer your question is no - @Transactional will have no effect if used to annotate private methods. The proxy generator will ignore them. When using proxies, you should apply the @Transactional annotation only to methods with public visibility.


1 Answers

What I don't understand is why do people say self invocation breaks transaction?

I never heard that self-invocation breaks transaction. All I know is that self-invocation will not start a new transaction and you already mentioned the reason why.

Snippet from Spring's Transaction Management Specification

Note 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.


If you remove @Transaction annotation from saveAB(), you would observe that method saveA() and saveB() would not run under transaction even though it is annotated with @Transactional. However, if you call saveA() or saveB() from outside the class, it will run under transaction as expected. That is the reason why people advice to be cautious with self-invocation.

public void saveAB(A a, B b)
{
    saveA(a);
    saveB(b);
}

@Transactional
public void saveA(A a)
{
    dao.saveA(a);
}

@Transactional
public void saveB(B b)
{
    dao.saveB(b);
}

In my view, self-invoking any public method is a bad idea.

like image 131
Kalyan Avatar answered Oct 07 '22 16:10

Kalyan