Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Understanding Spring transactions - What happens when a transactional method calls another transactional method?

Just to understand the workings of Spring transactions I want to know what happens in the following case where one method marked as @Transactional calls another method marked as @Transactional.

Assume a the configuration uses all default settings.

@Service("myService") @Transactional public MyService{    public void myServiceMethod(){       myDAO.getSomeDBObjects();    } }  @Repository("myDAO") @Transactional public MyDAOWithUsesBeyondMyService{    public void getSomeDBObjects(){...} } 

Now if I were to enter MyService.myServiceMethod() it would clearly start a transaction. Then, upon drilling into myDAO.getSomeDBObjects() what would happen? Would the fact that a transaction already exist cause no new transaction to be born, or am I creating two transactions here?

The documentation (quoted below) on Propagation seems to cover this, but I'd like to verify my understanding, it was a little much for my virgin brain to comprehend all at once.

Propagation: Typically, all code executed within a transaction scope will run in that transaction. However, you have the option of specifying the behavior in the event that a transactional method is executed when a transaction context already exists. For example, code can continue running in the existing transaction (the common case); or the existing transaction can be suspended and a new transaction created. Spring offers all of the transaction propagation options familiar from EJB CMT. To read about the semantics of transaction propagation in Spring, see Section 10.5.7, “Transaction propagation”.

like image 824
David Parks Avatar asked Nov 13 '10 08:11

David Parks


People also ask

What happens if one @transactional annotated method is calling another @transactional annotated method on the same object instance?

1 Answer. Show activity on this post. If you call method2() from method1() within the same class, the @Transactional annotation of the second method will not have any effect because it is not called through proxy, but directly.

What happens if a method annotated with @transactional calls another method annotated with @transactional?

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

What happens if a method annotated with @transactional?

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.

How does @transactional work in Spring?

So when you annotate a method with @Transactional , Spring dynamically creates a proxy that implements the same interface(s) as the class you're annotating. And when clients make calls into your object, the calls are intercepted and the behaviors injected via the proxy mechanism.


1 Answers

Two answers:

a) don't do it. Use @Transactional in the service layer or the dao layer, but not both (the service layer is the usual choice, as you probably want one transaction per service method)

b) if you do it, what happens depends on the propagation attribute of the @Transactional annotation and is described in this section: 10.5.7 Transaction propagation. Basically: PROPAGATION_REQUIRED means the same transaction will be used for both methods, while PROPAGATION_REQUIRES_NEW starts a new transaction.

About your comments:

Of course I kept reading and realized that, as I'm using proxies, this second method won't be managed by the transactional proxy, thus it's like any other method call.

That's not true in your situation (only if both methods were within the same class).

If a bean has methods a and b, and a calls b, then b is called on the actual method, not the proxy, because it is called from within the proxy (a bean doesn't know that it is proxied to the outside world).

proxy      bean   a() -->    a()             |             V   b() -->    b() 

In your situation, however, a service would have an injected dao object, which would be a proxy itself, so you'd have a situation like this:

           proxy      bean service    a() -->    a()                        |              /---------/              |                               V dao        b() -->    b() 
like image 173
Sean Patrick Floyd Avatar answered Sep 21 '22 20:09

Sean Patrick Floyd