Case1
#Transactional
public class UserServiceImpl implements UserService {
...................
public void method1(){
try{
method2();
}catch(Exception e){
}
}
public void method2(){
}
}
Case2
public class UserServiceImpl implements UserService {
...................
public void method1(){
try{
method2();
}catch(Exception e){
}
}
#Transactional
public void method2(){
}
}
In case1 if any exception occurs it rollback is working, but in case 2 it's not working. Is there any performance issues if I follow the case1?
In case 1 #Transactional is applied to every public individual method. Private and Protected methods are Ignored by Spring.
Spring applies the class-level annotation to all public methods of
this class that we did not annotate with #Transactional. However, if
we put the annotation on a private or protected method, Spring will
ignore it without an error.
In case 2 #Transactional is only applied to method2(), not on method1()
Case 1:
- Invoking method1() -> a transaction is started. When method1() calls method2() no new transaction is started, because there is already one
Case 2:
- Invoking method1() -> no transaction is started. When method1() calls method2() NO new transaction is started. This is because #Transactional does not work when calling a method from within the same class. It would work if you would call method2() from another class.
From the spring reference manual:
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.
#Transactionalon a class applies to each method on the service. It is a shortcut. Typically, you can set #Transactional(readOnly = true) on a service class, if you know that all methods will access the repository layer. You can then override the behavior with #Transactional on methods performing changes in your model. Performance issues between 1) and 2) are not known.
Suppose you have the following class:
#Transactional(readOnly = true)
public class DefaultFooService implements FooService {
public Foo getFoo(String fooName) {
// do something
}
// these settings have precedence for this method
#Transactional(readOnly = false, propagation = Propagation.REQUIRES_NEW)
public void updateFoo(Foo foo) {
// do something
}
}
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.
More info:
Transaction management in Spring
Quoting from here
The Spring team's recommendation is that you only annotate concrete classes with the #Transactional annotation, as opposed to annotating interfaces.
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!
Related
In Spring, beans are encapsulated by a proxy object and when called from outer object the proxy object's method is also called. By using this trick transaction management is performed in proxy object's methods.
But when you are calling a method in the same bean and if you want the called method to be run in another transaction with the caller method it is not possible. Since the method calls in the same bean does not pass through the proxy object which performs transaction operations.
In order to solve this, self-injection of the bean inside itself is proposed.
like this
#Service
public class MyService{
#Autowired
public MyService myService;
#Transactional(propagation = Propagation.REQUIRES_NEW)
public void method1(){
method2();// runs in the same transaction with method1
myService.method2();// runs in separate transaction from method1
}
#Transactional(propagation = Propagation.REQUIRES_NEW)
public void method2(){
}
}
I want to ask whether self-injection leads to memory leakage.
Outer bean MyService includes injected myService and myService should include attribute of type MyService, which should include attribute of type MyService ....
The service is not copied, it is only a reference. But I'd be wary of such a design: it creates a circular reference and the object graph is impossible to create at once. You first need to create the incomplete service, then set its field. Furthermore, it is kind of confusing and surprising to find such a dependency to self
I'd propose a different solution:
#Component
public class WithTransaction {
#Transactional(propagation = Propagation.REQUIRES_NEW)
public void requiresNew(final Runnable runnable) {
runnable.run();
}
}
#Service
public class MyService{
private final WithTransaction withTransaction;
#Autowired
public MyService(final WithTransaction withTransaction) {
this.withTransaction = withTransaction;
}
#Transactional(propagation = Propagation.REQUIRES_NEW)
public void method1(){
method2();// runs in the same transaction with method1
withTransaction.requiresNew(this::method2); // runs in separate transaction from method1
}
#Transactional(propagation = Propagation.REQUIRES_NEW)
public void method2(){
}
}
And if you can avoid it: don't call any public methods from your service on the service itself. Split the service into smaller components so that each "public" call must go through the proxy.
I wanted to make a method writing to DB as async using #Async annotation.
I marked the class with the annotation #EnableAsync:
#EnableAsync
public class FacialRecognitionAsyncImpl {
#Async
public void populateDataInPushQueue(int mediaId, int studentId) {
//myCode
}
}
while calling the populateDataInPushQueue method, the write operation should be executed in another thread and the flow should continue from the class I am calling this method. But this is not happening and the program execution is waiting for this method to complete.
The #Async annotation has few limitations - check whether those are respected:
it must be applied to public methods only
it cannot be called from the same class as defined
the return type must be either void or Future
The following can be found at the documentation of #EnableAsync:
Please note that proxy mode allows for the interception of calls through the proxy only; local calls within the same class cannot get intercepted that way.
Another fact is that the class annotated with #EnableAsync must be a #Configuration as well. Therefore start with an empty class:
#EnableAsync
#Configuration
public class AsyncConfiguration { }
In my opinion, you are missing #Configuration annotation and your async service is not component scanned. Here is an example code fragment that should do the trick:
#Configuration
#EnableAsync //should be placed together.
public class FacialRecognitionAsyncService {
#Async
public void populateDataInPushQueue(int mediaId, int studentId) {
//myCode
}
}
#Configuration
#EnableAsync
public class FacialServiceConfig {
// this will make your service to be scanned.
#Bean
public FacialRecognitionAsyncService createFacialRecognitionService() {
return new FacialRecognitionAsyncService();
}
}
Now the service bean that is invoking the async method. Notice that it has been dependency injected. This way spring AOP proxies will be invoked on each invocation fo the facialService. Spring uses AOP in the back scenes in order to implement #Async.
#Service
public class MyBusinessService {
#Autowire
FacialRecognitionAsyncService facialService;
public myBusinessMethod() {
facialService.populateDataInPushQueue()
}
Notice that FacialService is injected in MyService through dependency injection.
This question already has answers here:
Why does self-invocation not work for Spring proxies (e.g. with AOP)?
(2 answers)
Closed 2 years ago.
Suppose we have following class
#Service
class MyClass {
public void testA() {
testB();
}
#Transactional
public void testB() { ... }
}
Now, if we invoke myClass.testA(); in test, then #Transactional on testB will not take effect. The reason I think is following.
Cglib will create a proxy bean for MyClass, like this:
Class Cglib$MyClass extends MyClass {
#Override
public void testB() {
// ...do transactional things
super.testB();
}
}
Now we invoke myClass.testA(), which will invoke MyClass.testB() instead of Cglib$MyClass.testB(). So #Transactional is not effective. (Am I right?)
I tried to add #Transactional for both methods (i.e. testA() and testB()). The proxy class should like this.
Class Cglib$MyClass extends MyClass {
#Override
public void testA() {
// ...do transactional things
super.testA();
}
#Override
public void testB() {
// ...do transactional things
super.testB();
}
}
In this case, although we successfully invoke Cglib$MyClass.testA(), it will still goes to MyClass.testB().
So my conclusion is, two methods in same class invoking each other will make aop annotation fail to take effect, unless we use AopContext.currentProxy().
Am I right on above guess? Thanks very much for advice!
It is a well-known and documented (please search for the term "self-invocation") fact that Spring AOP, due to its proxy-based nature, does not and cannot capture internal method calls like this.someMethod(..).
So as you said, you either need to explicitly refer to the exposed proxy object or alternatively switch from Spring AOP to full AspectJ via load-time weaving.
You almost have it right. The proxy looks something more like this:
class Cglib$MyClass extends MyClass {
MyClass delegate;
#Override
public void testB() {
// ...do transactional things
delegate.testB();
}
}
Any call is forwarded by Spring which is why your nested annotations are not activated.
Also, if a virtual method like testA was overridden, Spring could not avoid to invoke the overridden method.
I am using spring aspect -around advice;
For super.method() or inter class method call, I am unable to call my aspect code;
This is my code sample.
//My aspect Class
#Aspect
public class MyAspect {
#Around("execution(* in.test.project.service.myservice.create(..))")
public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable {
// .
//my logic
// .
}
public interface Myservice{
void create(Myclass entity);
void createObject(Myclass entity);
}
class myserviceImpl implements Myservice{
public void create(Myclass entity) {
// TODO Auto-generated method stub
}
void createObject(Myclass entity){
create(entity);
}
}
class Mycontroller {
void test(Myclass entity) {
Myservice myservice = new myserviceImplimplements();
// calls MyAspect code
myservice.create(entity);
// MyAspect not called
myservice.createObject(entity);
}
}
This a limitation of using Spring AOP without having your code know that it is using Spring AOP (you can view Spring's documentation on how you could do this as well as why you shouldn't on their "Understanding AOP proxies" page). Spring AOP is a proxy-based system and differentiates between the proxy object itself (bound to this) and the target object behind the proxy (bound to target), so you are also limited in what kinds of pointcuts you can apply.
Since the call first goes through the proxy and then on the object, calls made inside of the object on that object (like the call you have above that calls a method inside) are called on the Object itself and not the proxy. The calls that go through the proxy can delegate to relevant interceptors, while calls that are made by the Object itself do not proxy, and thus can not be advised by Spring AOP like this. The link I provided above shows to expose the AopContext, but I would highly recommend against doing that.
I have 3 Spring Components calling first->second->third.
If I only have #Transactional annotation on first and third will transaction be propagated properly?
#Component public class C1 {
#Autowired C2 c2;
#Transactional public method1() {
...
c2.method2();
}
}
#Component public class C2 {
#Autowired C3 c3;
public method2() {
...
c3.method3();
}
}
#Component public class C3 {
#Transactional public method3() {
...
}
}
Yes, Transaction support is thread-bound. When method2() is executing, it does so in the same Thread and therefore has access to the current Transaction. The same goes for method3().
#Transactional works as below
if its marked on any method then we can specify an attribute called propagation whose value could be Required by default or RequiredNew.
sample is
#Transactional(readOnly = true,propagation=Propagation.REQUIRES_NEW)
public void somemethod(){
anotherMethod();
}
if the attribute is just "Required" which is there by default then it maintains a single transaction for whole propogation of all methods no matter whether you declare #transactional in each method or not.
so all methods execution comes under same transaction and if any rollback happens in last method it affects til the method called.
if the attribute is set to "RequiredNew" then each method runs in their own tranactions so rollback in one method does not rollback other methods tranactions.
hope you are clear now