Does Spring @Transactional Attribute Work on a Private Method

Does Spring @Transactional attribute work on a private method?

The Question is not private or public, the question is: How is it invoked and which AOP implementation you use!

If you use (default) Spring Proxy AOP, then all AOP functionality provided by Spring (like @Transactional) will only be taken into account if the call goes through the proxy. -- This is normally the case if the annotated method is invoked from another bean.

This has two implications:

  • Because private methods must not be invoked from another bean (the exception is reflection), their @Transactional Annotation is not taken into account.
  • If the method is public, but it is invoked from the same bean, it will not be taken into account either (this statement is only correct if (default) Spring Proxy AOP is used).

@See Spring Reference: Chapter 9.6 9.6 Proxying mechanisms

IMHO you should use the aspectJ mode, instead of the Spring Proxies, that will overcome the problem. And the AspectJ Transactional Aspects are woven even into private methods (checked for Spring 3.0).

Spring transaction when calling private method

Yes, there will be a rollback.
The private methods will run within the same transaction. You should be aware that you can't have a @Transactional private method. It will not work without raising any error. This behavior is explained in Spring Docs:

Due to the proxy-based nature of Spring’s AOP framework, calls within
the target object are by definition not intercepted. For JDK proxies,
only public interface method calls on the proxy can be intercepted.

Public method with @Transactional calling private method

As per Spring Documentation

Spring recommends that you only annotate concrete classes (and methods
of concrete classes) with the @Transactional annotation, as opposed to
annotating interfaces. You certainly can place the @Transactional
annotation on an interface (or an interface method), but this works
only as you would expect it to if you are using interface-based
proxies. The fact that Java annotations are not inherited from
interfaces means that if you are using class-based proxies (
proxy-target-class="true") or the weaving-based aspect (
mode="aspectj"), then the transaction settings are not recognized by
the proxying and weaving infrastructure, and the object will not be
wrapped in a transactional proxy, which would be decidedly bad.

So, I would recommend to use @Transaction at method createRecord() level or RepoImpl class level.

All code within a transaction scope runs in that transaction. However, you can specify the behavior if a transactional method is run when a transaction context already exists.

When a method without @Transactional is called within a transaction block, the parent transaction will continue to exist for the new method. It will use the same connection from the parent method (method with @Transactional) and any exception caused in the called method (method without @Transactional) will cause the transaction to rollback as configured in the transaction definition.

Since this mechanism is based on proxies, only 'external' method calls coming in through the proxy will be intercepted. This means that 'self-invocation', i.e. a method within the target object calling some other method of the target object, won't lead to an actual transaction at runtime even if the invoked method is marked with @Transactional.

Spring: A method who call a transactional method has to be transactional?

The transaction is implemented through a proxy. Calls from within the object (such as code within methodB) don't go through the proxy.

You can have one nontransactional service, and one transactional service, and inject the transactional service into the other, so you can call a transactional method from the nontransactional service and go through the proxy. That way you can keep the boundaries you want on your transaction.

Why doesn't Spring's @Transactional work on protected methods?

Because of this:

In proxy mode (which is the default), only 'external' method calls coming in through the proxy will be intercepted. This means that 'self-invocation', i.e. a method within the target object calling some other method of the target object, won't lead to an actual transaction at runtime even if the invoked method is marked with @Transactional!

And this:

Due to the proxy-based nature of Spring's AOP framework, protected methods are by definition not intercepted, neither for JDK proxies (where this isn't applicable) nor for CGLIB proxies (where this is technically possible but not recommendable for AOP purposes). As a consequence, any given pointcut will be matched against public methods only!

The Spring guys would probably want to keep consistency with JDK proxies. You wouldn't want to have different proxy configuration and different results based on JDK versus CGLIB.

@Transactional propagation on private methods


  1. If myPrivateMethod is called from public method that is annotated @Transactional it is propagated.
  2. If first condition is TRUE yes it will roll-back.
  3. It is misconception to compare isolation level on database and synchronization of class method. They shouldn't be compared at all. If your method will be used in multi-thread env you should synchronize method(be aware in some circumstances it is not enough to have thread safe code). Isolation level SERIALIZABLE is used on database level. It is most restrictive isolation level, and it can lock a lot of tables when you run some query, before it is is done, to help your data not turn to some inconsistent state. You should be sure that you need this level of isolation because this can lead to performance issues. So answer is NO.

Should @Transactional method roll back in case of calling a private method which throws RuntimeException in Spring?

The optimal/usual result is rollback as you answered, but interviewer said general statement as it depends

Maybe the interviewer meant to check if you know when it won't rollback as expected

Meaning that you shouldn't assume @Transactional is actually working, it should be checked first, because if @Transactional isn't working there'll be no rollback.

For example, in case of calling transactional method in same class, if method1() is called from method3() in same class @Transactional won't work and won't rollback

Spring Boot With @Transactional annotated method, calls other transactional methods and throws an Exception

Make sure that the method annotated with @Transactional is declared as public and called by a different class.

A transactional method must be public so that Spring can override it and it must be called from outside the defining class so that the invocation can go through a proxy.

It's one of the common pitfalls when using @Transactional, for more information see https://codete.com/blog/5-common-spring-transactional-pitfalls/



Related Topics



Leave a reply



Submit