Search code examples
javaspringtransactionalpropagation

What is the difference between a method with @Transactional(propagation = Propagation.SUPPORTS) and method without @Transactional?


What is the difference between method with

@Transactional(propagation = Propagation.SUPPORTS)

and a method without @Transactional?

For example:

public class TEst {

    @Transactional
    public void methodWithTransaction1(){
        methodWithSupportsTransaction();
    }

    @Transactional
    public void methodWithTransaction2(){
        methodWithoutTransactional();
    }

    @Transactional(propagation = Propagation.SUPPORTS)
    public void methodWithSupportsTransaction(){

    }

    public void methodWithoutTransactional(){

    }
}

Solution

  • Except for the slight difference indicated in the javadoc regarding synchronization, a difference between both is that a transactional proxy intercepts the method call if the method is annotated with Transactional, and will mark the current transaction, if any, as rollbackOnly if a runtime exception is thrown from that method.

    So, let's take an example:

    public class A {
        @Autowired B b;
    
        @Transactional
        public void foo() {
            try {
                b.bar();
            }
            catch (RuntimeException e) {
                // ignore
            }
    
            ...
        }
    }
    
    public class B {
        // @Transactional(propagation = Propagation.SUPPORTS)
        public void bar() {
            throw new RuntimeException();
        }
    }
    

    Calling a.foo() will start a transaction if none exists yet (propagation REQUIRED). Then b.bar() will be called and will throw an exception. The exception is caught by a.foo(), which continues executing as if nothing happened. At the end of a.foo(), the transaction will be committed successfully.

    Now let's uncomment the Transactional annotation on b.bar(). Calling a.foo() will start a transaction if none exists yet (propagation REQUIRED). Then b.bar() will be called and will throw an exception. This exception will be "intercepted" by the transactional proxy around B, which will mark the transaction to rollbackOnly. Then the exception will propagate to A. a.foo(). The exception is caught by a.foo(), which continues executing as if nothing happened. At the end of a.foo(), the transaction will be committed, but that commit will fail because the transaction has already been marked as rollbackOnly. The caller of a.foo() will get a TransactionSystemException.