Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring @Transactional doesn't work for an annotated method when called from within service class

In below code , when methodInner() is called from within methodOuter, should be under transaction bounds. But it is not. But when methodInner() is called directly from MyController class , it is bound by transaction. Any explanations?

This is controller class.

@Controller
public class MyController {

    @Autowired
    @Qualifier("abcService")
    private MyService serviceObj;

    public void anymethod() {
        // below call cause exception from methodInner as no transaction exists  
        serviceObj.methodOuter(); 
    }

}

This is service class.

@Service("abcService")
public class MyService {

    public void methodOuter() {
        methodInner();
    }

    @Transactional
    public void methodInner() {
    .....
    //does db operation.
    .....
    }
}
like image 504
cyrilantony Avatar asked Sep 26 '14 11:09

cyrilantony


People also ask

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

It is not sufficient to tell you simply to annotate your classes with the @Transactional annotation, add the line ( <tx:annotation-driven/> ) to your configuration, and then expect you to understand how it all works.

What happens if one @transactional annotated method is calling another @transactional annotated method inside a same object instance?

If you call a method with a @Transactional annotation from a method with @Transactional within the same instance, then the called methods transactional behavior will not have any impact on the transaction.

Can @transactional annotation only be used at class level?

Annotation Type Transactional. Describes a transaction attribute on an individual method or on a class. When this annotation is declared at the class level, it applies as a default to all methods of the declaring class and its subclasses.

Can we use @transactional in service layer?

The @Transactional annotation belongs to the Service layer because it is the Service layer's responsibility to define the transaction boundaries.


1 Answers

Spring uses Java proxies by default to wrap beans and implement annotated behavior. When doing calls within a service you bypass proxy and run method directly, so annotated behavior is not triggered.

Possible solutions:

  1. Move all @Transactional code to separate service and always do calls to transactional methods from outside

  2. Use AspectJ and weaving to trigger annotated behavior even within a service

like image 90
hoaz Avatar answered Oct 11 '22 08:10

hoaz