سؤال

In my understanding newPrint method in the following code should create a new transaction but apparently it prints out the same transaction-status object as was used in oldPrint method. I am calling oldPrint from another class. Is it because newPrint is being called using this? If yes, then when will a new transaction get created? If I call both methods from another class two separate transaction will be created anyway because @Transactional is used at class level.

@Transactional
public class Unsubcriber {


    @Transactional(readOnly = false, propagation = Propagation.REQUIRES_NEW)
    public void newPrint() {
        System.out.println(TransactionAspectSupport.currentTransactionStatus());
    }

    public void oldPrint() {

        System.out.println(TransactionAspectSupport.currentTransactionStatus());
        newPrint();
    }

Output:

org.springframework.transaction.support.DefaultTransactionStatus@3bacd0e7
org.springframework.transaction.support.DefaultTransactionStatus@3bacd0e7

What would be the scenario when Propagation.REQUIRES_NEW would work?

هل كانت مفيدة؟

المحلول 3

What you are seeing is a class misconception about Spring AOP.

Since newPrint() is being called from a method inside the same class, no advice is triggered and therefor no handling for transactional takes place.

Had you called the method newPrint() outside the class, a new transaction would be created whether or not the caller already participated in a transaction.

Since you have used @Transactional on the class, every method get's the default @Transactional settings and that is why you actually have a transaction.

Take a look at this section of the Spring reference documentation for a detailed discussion on how AOP works in Spring.

A total hack to get your code working like you expect would be the following:

((Unsubcriber ) AopContext.currentProxy()).newPrint();

This solution is mentioned in various places among which is this SO post.

نصائح أخرى

Assuming geoand's edit clarification is true, the answer to your question is Spring uses AOP proxies to apply the transaction restrictions. So, this will work when calls come into you Unsubscriber from outside, which can then be intercepted and the transaction boundaries can be applied. If you're calling it from within your class, as you said, using 'this', then there is no proxying that can be done and hence your @Transactional will not come into play.

Here are few rules of @Transactional worth mentioning

1.@Transactional annotations only work on public methods. If you have a private or protected method with this annotation there’s no (easy) way for Spring AOP to see the annotation. It doesn’t go crazy trying to find them so make sure all of your annotated methods are public.

2.Transaction boundaries are only created when properly annotated (see above) methods are called through a Spring proxy. This means that you need to call your annotated method directly through an @Autowired bean or the transaction will never start. If you call a method on an @Autowired bean that isn’t annotated which itself calls a public method that is annotated YOUR ANNOTATION IS IGNORED. This is because Spring AOP is only checking annotations when it first enters the @Autowired code.

Source - http://blog.timmattison.com/archives/2012/04/19/tips-for-debugging-springs-transactional-annotation/

Calling a method from within a class (using this) means that it will not go through the transaction initialisation contained within Spring's proxy object. Since the this keyword is a pointer to an instance of your original object, not the transaction aware, enhanced Spring object.

The annotations will work as expected in scenarios such as:

object1.oldPrint();
object1.newPrint();
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top