Spring - @Transactional - What Happens in Background

Spring - @Transactional - What happens in background?

This is a big topic. The Spring reference doc devotes multiple chapters to it. I recommend reading the ones on Aspect-Oriented Programming and Transactions, as Spring's declarative transaction support uses AOP at its foundation.

But at a very high level, Spring creates proxies for classes that declare @Transactional on the class itself or on members. The proxy is mostly invisible at runtime. It provides a way for Spring to inject behaviors before, after, or around method calls into the object being proxied. Transaction management is just one example of the behaviors that can be hooked in. Security checks are another. And you can provide your own, too, for things like logging. 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.

Transactions in EJB work similarly, by the way.

As you observed, through, the proxy mechanism only works when calls come in from some external object. When you make an internal call within the object, you're really making a call through the this reference, which bypasses the proxy. There are ways of working around that problem, however. I explain one approach in this forum post in which I use a BeanFactoryPostProcessor to inject an instance of the proxy into "self-referencing" classes at runtime. I save this reference to a member variable called me. Then if I need to make internal calls that require a change in the transaction status of the thread, I direct the call through the proxy (e.g. me.someMethod().) The forum post explains in more detail.

Note that the BeanFactoryPostProcessor code would be a little different now, as it was written back in the Spring 1.x timeframe. But hopefully it gives you an idea. I have an updated version that I could probably make available.

Spring managed transactions @Transactional annotation

Spring transaction default is

@Transactional(propagation = Propagation.REQUIRED)

So you do not need to specify the propagation property.

So, What does it mean by @Transactional annotation for a spring component ?

  • Spring framework will start a new transaction and executes all the method and finally commit the transaction.

  • But If no transaction is exists in the application context then spring container will start a new transaction.

  • If more than one method configured as Propagation.REQUIRED then transactional behavior assigned in a nested way to each method in logically but they are all under the same physical transaction.

So, What is the result ?

The result is if any nested transaction fail, then the whole transaction will fail and rolled back (do not insert any value in db) instead of commit.

Example:

@Service
public class ServiceA{

@Transactional(propagation = Propagation.REQUIRED)
public void foo(){
fooB();
}

@Transactional(propagation = Propagation.REQUIRED)
public void fooB(){
//some operation
}

}

Explanation :
In this example foo() method assigned a transactional behavior and inside foo() another method fooB() called which is also transactional.
Here the fooB() act as nested transaction in terms of foo(). If fooB() fails for any reason then foo() also failed to commit. Rather it roll back.

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

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()

Spring Transaction Management @Transactional behavior

Example 1: As you are calling the createPDF method from inside your Service, the @Transactional(REQUIRES_NEW) annotation will effectively be ignored. There will be no new transaction opened.

Example 2: As your are calling another service, which is wrapped in a transactional proxy, you will get a new transaction, as the annotation is respected.

You also might want to read up on this article: Spring Transaction Management: @Transactional In-Depth



Related Topics



Leave a reply



Submit