Spring Transaction Propagation

Spring framework provides excellent support for Transaction Management. To manage a transaction in Spring all we need to do is annotate a Spring bean's method with @Transactional, its that simple. Spring provides different propagation levels to manage propagation of transaction between different Spring beans. This article will be focused on understanding the different propagation level available in Spring Transactions.


Transaction Propagation Levels

Below are the available Transaction Propagation Levels in Spring:

  • REQUIRED (Default)
  • REQUIRES_NEW
  • SUPPORTS
  • NOT_SUPPORTED
  • MANDATORY
  • NEVER
  • NESTED

To apply propagation to a transaction we need to pass it as a parameter with the @Transactional annotation:

@Transactional(propagation=Propagation.REQUIRED)
public void startTransaction(){...}

Note: Spring Transactions are proxy based, which means they are applied using AOP. Thus all transaction methods must have public visibility so that they can be accessed from outside the class.

Also Spring proxies intercepts method calls on beans to apply the transactional behaviour, thus when two methods within the same bean are annotated with transactional and one method called from within another method, Spring would not get a chance to intercept the call. This beans the called method would execute in the same transactional context irrespective of the propagation levels assigned to it.


REQUIRED

REQUIRED is the default propagation level if none is specified. A method with REQUIRED propagation would continue to execute in the current transaction if one exists, else create a new transaction.

Consider a scenario of mobile recharge, let's say it has two steps involved:

  1. Debit Bank Account
  2. Credit Mobile Balance

Here we want our transaction to complete only when both step 1 and 2 are complete. We don't want to debit the bank account when due to some reason we are not able to credit the mobile balance. In this case we require a REQUIRED propagation level. Thus here we logically have two transaction but they are part of a single physical transaction. This means if the inner transaction fails the outer transaction will also rollback.

@Autowired
private BankDao accountDao;

@Autowired
private MobileService mobileService;

@Transactional(propagation=Propagation.REQUIRED)
public void debitAccount(){
    try{
        accountDao.debitAccount();
        mobileService.creditBalance();    
    }
    catch(Exception re){
        re.printStackTrace();
    }    
}
@Autowired
private MobileDao mobileDao;

@Transactional(propagation=Propagation.REQUIRED)
public void creditBalance(){
    mobileDao.updateBalance();
}

REQUIRES_NEW

A REQUIRES_NEW method would create its own physical transaction, if a transaction already exist it would be suspended and resumed after this transaction is completed. Thus if an inner transaction marked with REQUIRES_NEW propagation is rolled back it does not impact the outer transaction.

As an example lets add a 3rd step to our scenario earlier. Let's say we need to send a message to the user after successful recharge.

Here we do not mind if the 3rd transaction fails for any reason, we would still want our earlier two steps to complete irrespective to what happens to the message. We do not want our user to not get this mobile recharge just because we were not able to send him a message.

@Transactional(propagation=Propagation.REQUIRES_NEW)
public void sendMessage() {		
    throw new RuntimeException();
}

SUPPORTS

A method with SUPPORTS propagation would continue to execute within the current transaction if one exists, else would execute non-transactionally.


NOT_SUPPORTED

A method with NOT_SUPPORTED propagation would always execute non-transactionally. If a current transaction already exists it would be suspended till this method completes.


MANDATORY

A method with MANDATORY propagation always execute transactionally. A current transaction should always already exists, it would continue with the current transaction. If no transaction exists it throws an exception.


NEVER

Similar to NOT_SUPPORTED, would always execute non-transactionally. If a current transaction already exist it throws an exception.


NESTED

As the name suggest it is used with nested transaction. It is mostly used to have savepoints in a transaction. At the start of every nested transaction a savepoint will be taken. In case of any failure of the nested transaction we would rollback to the savepoint. Since nested transaction is a part of the outer transaction, it is only committed when the outer transaction commits. 


Download Source Code

You can download the source code of the Sample Spring Application discussed in this article.

POPULAR ARTICLES

Creating Conditional Beans in Spring

The concept of condition beans enables Spring to restrict the creation of any bean depending on the evaluation of a condition. These beans get created only when a preset condition is evaluated as true

View Article

Accepting Request Param and Path Variable in Spring Controller

Spring MVC provides various ways through which a client browser can pass data to the Controller. In this article we will discuss about accepting Request Parameters and Path Variables in Spring Contr..

View Article

Generate Namespace & Schema Information using JAXB

Most xml documents used in enterprise applications makes use of namespace to avoid element name conflicts. This article talks about generating these namespace and schema information when marshaling...

View Article

Switching Database Profile using Spring Profiles

We are most likely to have separate db configuration for different environment like development and production environment. Spring profiles provide a convenient way to switch db profiles at runtime.

View Article

SQL and its Sub-Languages

SQL (Structured Query Language) is a language understood by most modern databases. It is an ANSI (American National Standard Institute) standard language which is used to manipulate databases.

View Article

Introducing JUnit Rule

Junit Rules allows developers to add additional functionalities that can applied to all test methods in a test class. It is similar to the concept of custom test runners but with reduced restrictions.

View Article

Addressing Ambiguity in Spring Autowiring

Spring autowiring is powerful concept, but we should be very cautious while using it. We may end up in creating ambiguity while autowiring beans, which will cause autowiring to fail.

View Article

Creating and Using Synonym in Oracle Database

Synonyms are database objects used to provide duplicate names to existing objects in the database. It is just an alternate name used to hide the original name of the object.

View Article

Creating and Using Sequence in Oracle Database

A sequence is used to auto-generate numbers in ascending or descending order which can serve as a primary key or a part of it (in case of composite key).

View Article

Creating and Manipulating Constraints in Oracle Database

Constraints are used to impose certain rules on columns to avoid invalid data entry into the table. If any of the constraint is violated the operation fails.

View Article

Integrating Log4J with Perf4J for Performance Logging

Perf4j is an open source logging framework used primarily for monitoring performance statistics in java applications. Log4j has the ability to integrate with perf4j to capture performance data.

View Article

Tagging in GIT

Tagging allows us to mark a specific point in the commit history or snapshot. A tag is typically used to mark a project release. This article shows how to create tags in Git.

View Article