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
- If myPrivateMethod is called from public method that is annotated @Transactional it is propagated.
- If first condition is TRUE yes it will roll-back.
- 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
Non Resizable Window Border and Positioning
Java 7 Language Features with Android
The Following Classes Could Not Be Instantiated: - Android.Support.V7.Widget.Toolbar
Setting/Changing the Ctime or "Change Time" Attribute on a File
How to Get Chromedriver Process Pid Using Java
Growing Resident Size Set in Jvm
Load Native Libraries in an Eclipse Rcp Application on Linux
How to Fix Java.Awt.Headlessexception in Jenkins on Linux
How to Instantiate an Abstract Class
How to Change a Jfreechart'S Size
Why Does Arrayindexoutofboundsexception Occur and How to Avoid It in Android
How to Convert a Color Integer to a Hex String in Android
Permission to Write to the Sd Card
How to Find My Pid in Java or Jruby on Linux