Difference Between Spring Transaction Propagation Attributes In Java Development

This post explains how the Spring Transaction Propagation Attributes -- Propagation.Requires_New and Propagation.Required -- are different. You need to read this post thoroughly to understand what they want to say. I have also explained JPA technology and Spring technology in the beginning.



Propagation.REQUIRES_NEW v/s Propagation.REQUIRED

Technology


JPA stands for the Java Persistence API which is the standard from Sun Microsystems for persistence. ORM stands for Object Relational Mapping. JPA is the standard for ORM. If a framework has to say ORM, then it should implement all the specifications given by JPA. JPA is just specification. It needs a persistence provider for CRUD operations. Hibernate, Eclipse link, etc are the examples of persistence providers. "Spring" is one of the widely used enterprise application frameworks that gives immense integration support to the existing tools for java web development, GUI, and mobile as well.

Technologies

Spring, JPA and Hibernate, Maven, MySQL database

Usecase

If you are working in spring transaction management, then you will be seeing @Transactional annotation on top of either method or class, which indicates that spring will take care of entity persistence. But, there are several attributes which will affect the transaction execution.

For example

PROPAGATION_SUPPORTS, PROPAGATION_REQUIRES_NEW, PROPAGATION.REQUIRED etc. and many others are there.

In this document, you will find the two attributes' usage: Propagation.REQUIRED and Propagation.REQUIRES_NEW. The main difference between them is, if a method in Spring Business Activity/DAO class is annotated with Propagation.REQUIRES_NEW, then when the execution comes to this method, it will create a new transaction irrespective of the existing transaction whereas if the method is annotated with Propagation.REQUIRED, spring checks for any existing transaction. If yes, it uses that old transaction otherwise it creates a new one.

But, the disadvantage of Propagation.REQUIRES_NEW is that even if the inner method fails to execute (because of some exception), the outer method commits the transaction. That causes inconsistency in data. If you use Propagation.REQUIRED, then if both inner/outer methods execute without fail, then only the data will be persisted to the database.

Let’s prove this. For that, we need 5 steps.

There are 4 steps to create the page.

  1. Create the project with JPA/ Hibernate, Spring.
  2. Create persistence.xml file, Spring.xml.
  3. Create Entity, Business classes
  4. Run the application.

Step 1 Create project structure



Project structure will be like the above.

If you look at the project structure, it’s a maven project and POM.XML is the mandatory file in it. In this maven file, we can configure dependencies for JPA, hibernate, Java, database, spring etc. I am using MySQL database for data storage.

Three packages are needed - one for entity, one for business logic, one for application testing. There’s a spring.xml file which is used to define Business Activity/DAO classes, data sources, entity manager factory, etc. And, the persistence.xml file is used to define persistence unit and its credentials.

Step 2

spring.xml

  1. <?xmlversion="1.0"encoding="UTF-8"?>  
  2.     <beansxmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:p="http://www.springframework.org/schema/p" xsi:schemaLocation="http://www.springframework.org/schema/beans  
  3. http://www.springframework.org/schema/beans/spring-beans-3.0.xsd  
  4. http://www.springframework.org/schema/context  
  5. http://www.springframework.org/schema/context/spring-context-3.0.xsd   
  6. http://www.springframework.org/schema/tx  
  7. http://www.springframework.org/schema/tx/spring-tx.xsd">  
  8.   
  9.         <tx:annotation-driven/>  
  10.         <context:component-scanbase-package="jpa.transaction.scopes.business" />  
  11.         <beanid="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">  
  12.             <propertyname="driverClassName" value="com.mysql.jdbc.Driver" />  
  13.             <propertyname="url" value="jdbc:mysql://localhost:3306/employee" />  
  14.             <propertyname="username" value="root" />  
  15.             <propertyname="password" value="root" />  
  16.             </bean>  
  17.   
  18.             <beanid="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">  
  19.                 <propertyname="persistenceUnitName" value="jpa-example" />  
  20.                 <propertyname="dataSource" ref="dataSource" />  
  21.                 </bean>  
  22.                 <beanid="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">  
  23.                     <propertyname="entityManagerFactory" ref="entityManagerFactory" />  
  24.                     </bean>  
  25.                     <beanid="empBA" class="jpa.transaction.scopes.business.EmpBABean">  
  26.                         </bean>  
  27.                         <beanid="employeeBA" class="jpa.transaction.scopes.business.EmployeeBABean">  
  28.                             <propertyname="empBA" ref="empBA" />  
  29.                      </bean>  
  30.             </beans>  
Here, we are saying that transacting the data source will be defined and the data source will be injected by spring framework to the entity manager factory. Transaction manager will be from spring.

Business Activity/DAOs and their dependencies are defined. Spring will inject the dependencies.

Persistence.xml
  1. <persistencexmlns="http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence  
  2. http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd" version="2.1">  
  3.     <persistence-unitname="jpa-example" transaction-type="RESOURCE_LOCAL">  
  4.         <provider>org.hibernate.ejb.HibernatePersistence</provider>  
  5.   
  6.         </persistence-unit>  
  7.    </persistence>  
Here, the persistence provider is defined. As we have defined the data source in spring.xml file already, there is no need to define JDBC attributes here.

Step 3

EmployeeBE.java

This is the entity class which is going to be persisted in database.
  1. // Import statements  
  2.   
  3. @NamedQueries({  
  4.     @NamedQuery(name = EmployeeBE.FIND_ALL, query = "SELECT e FROM EmployeeBE e order by e.name "),  
  5. })  
  6. @Entity  
  7. @Table(name = "T_EMP")  
  8. publicclassEmployeeBEimplements Serializable{  
  9. privatestaticfinallongserialVersionUID = 1607726899931733607L;  
  10.       
  11.     publicstaticfinal String FIND_ALL = "naveen.examples.jpa.entity.EmployeeBE.find_all";  
  12.   
  13.     @Id  
  14.     @GeneratedValue(strategy = GenerationType.AUTO)  
  15.     privateintid;  
  16.   
  17.     @Column(name = "NAME")  
  18.     private String name;  
  19.   
  20.     @Column(name = "version_num")  
  21.     @Version  
  22.     privateintversion;  
  23.   
  24. // Getters and setters}  
  25.   
  26. // Interface for CRUD operations.  
  27. packagejpa.transaction.scopes.business;  
  28. importjpa.transaction.scopes.entity.EmployeeBE;  
  29. publicinterfaceEmpBA {  
  30.     publicvoidsaveEmployee(EmployeeBEnewEmp);  
  31. }  
  32. packagejpa.transaction.scopes.business;  
  33. importjavax.persistence.EntityManager;  
  34. importjavax.persistence.PersistenceContext;  
  35.   
  36. importorg.springframework.transaction.annotation.Propagation;  
  37. importorg.springframework.transaction.annotation.Transactional;  
  38.   
  39. importjpa.transaction.scopes.entity.EmployeeBE;  
  40.   
  41. publicclassEmpBABeanimplementsEmpBA {  
  42.   
  43.     @PersistenceContext  
  44.     privateEntityManagerentityManager;  
  45.   
  46.     @Transactional(propagation = Propagation.REQUIRES_NEW)  
  47.     publicvoidsaveEmployee(EmployeeBEnewEmp) {  
  48.         entityManager.persist(newEmp);  
  49.         thrownewIllegalArgumentException("Exception Occured");  
  50.     }  
  51.       
  52. }  
  53.   
  54. packagejpa.transaction.scopes.business;  
  55. importjpa.transaction.scopes.entity.EmployeeBE;  
  56. publicinterfaceEmployeeBA {  
  57.     publicvoidsaveUser(EmployeeBEemployeeBE);  
  58.       
  59. }  
  60.   
  61.   
  62. packagejpa.transaction.scopes.business;  
  63.   
  64. importjavax.persistence.EntityManager;  
  65. importjavax.persistence.PersistenceContext;  
  66.   
  67. importorg.springframework.transaction.annotation.Propagation;  
  68. importorg.springframework.transaction.annotation.Transactional;  
  69.   
  70. importjpa.transaction.scopes.entity.EmployeeBE;  
  71.   
  72. @Transactional  
  73. publicclassEmployeeBABeanimplementsEmployeeBA {  
  74.   
  75.     @PersistenceContext  
  76.     privateEntityManagerentityManager;  
  77.   
  78.     privateEmpBAempBA;  
  79.   
  80.     @Transactional(propagation = Propagation.REQUIRES_NEW)  
  81.     publicvoidsaveUser(EmployeeBEemployeeBE) {  
  82.         entityManager.persist(employeeBE);  
  83.         try{  
  84.             EmployeeBEnewEmp = newEmployeeBE();  
  85.             newEmp.setName("Sachin");  
  86.             empBA.saveEmployee(newEmp);  
  87.         }catch(Exception e){  
  88.             e.printStackTrace();  
  89.         }  
  90.     }  
  91.   
  92.     publicEmpBAgetEmpBA() {  
  93.         returnempBA;  
  94.     }  
  95.   
  96.     publicvoidsetEmpBA(EmpBAempBA) {  
  97.         this.empBA = empBA;  
  98.     }  
  99. }  
If you look at the above code snippets, we have,
  1. Two Interface, EmpBA, EmployeeBAdefines business methods
  2. EmpBABean, EmployeeBABean, implementation of business methods

In the Business Activity/DAO classes, if you observe, these classes are annotated with @Transactional; that means transaction will be handled by spring, like beginning the transaction, committing and closing the transaction.

Methods are annotated with propagation attribute REQUIRED_NEW in both classes.

POM.xml

  1. <projectxmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">  
  2.     <modelVersion>4.0.0</modelVersion>  
  3.   
  4.     <groupId>jpa</groupId>  
  5.     <artifactId>transaction.scopes</artifactId>  
  6.     <version>0.0.1-SNAPSHOT</version>  
  7.     <packaging>jar</packaging>  
  8.   
  9.     <name>transaction.scopes</name>  
  10.     <url>http://maven.apache.org</url>  
  11.   
  12.     <properties>  
  13.         <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>  
  14.         <spring.version>3.2.5.RELEASE</spring.version>  
  15.         <hibernate.version>4.1.9.Final</hibernate.version>  
  16.     </properties>  
  17.   
  18.     <dependencies>  
  19.   
  20.         <dependency>  
  21.             <groupId>org.springframework</groupId>  
  22.             <artifactId>spring-core</artifactId>  
  23.             <version>${spring.version}</version>  
  24.         </dependency>  
  25.   
  26.         <dependency>  
  27.             <groupId>org.springframework</groupId>  
  28.             <artifactId>spring-context</artifactId>  
  29.             <version>${spring.version}</version>  
  30.         </dependency>  
  31.   
  32.         <dependency>  
  33.             <groupId>org.springframework</groupId>  
  34.             <artifactId>spring-tx</artifactId>  
  35.             <version>${spring.version}</version>  
  36.         </dependency>  
  37.   
  38.         <dependency>  
  39.             <groupId>org.springframework</groupId>  
  40.             <artifactId>spring-orm</artifactId>  
  41.             <version>${spring.version}</version>  
  42.         </dependency>  
  43.   
  44.         <dependency>  
  45.             <groupId>org.hibernate</groupId>  
  46.             <artifactId>hibernate-core</artifactId>  
  47.             <version>${hibernate.version}</version>  
  48.         </dependency>  
  49.   
  50.         <dependency>  
  51.             <groupId>org.hibernate</groupId>  
  52.             <artifactId>hibernate-entitymanager</artifactId>  
  53.             <version>${hibernate.version}</version>  
  54.         </dependency>  
  55.   
  56.         <dependency>  
  57.             <groupId>commons-dbcp</groupId>  
  58.             <artifactId>commons-dbcp</artifactId>  
  59.             <version>1.2.2</version>  
  60.         </dependency>  
  61.   
  62.         <dependency>  
  63.             <groupId>mysql</groupId>  
  64.             <artifactId>mysql-connector-java</artifactId>  
  65.             <version>5.1.31</version>  
  66.         </dependency>  
  67.   
  68.     </dependencies>  
  69.     </project>  
Dependencies for spring, hibernate, MySQL will be defined here. Spring ORM, spring transaction management dependencies, and core modules will be defined here.

Step 4 Run the application
  1. packagejpa.transaction.scopes;  
  2.   
  3. importorg.springframework.context.ApplicationContext;  
  4. importorg.springframework.context.support.ClassPathXmlApplicationContext;  
  5.   
  6. importjpa.transaction.scopes.business.EmployeeBA;  
  7. importjpa.transaction.scopes.entity.EmployeeBE;  
  8.   
  9. publicclassApplcation {  
  10.       
  11.     @SuppressWarnings("resource")  
  12.     publicstaticvoid main(String[] args) {  
  13.           
  14.         ApplicationContextctx = newClassPathXmlApplicationContext(  
  15.         "spring.xml");  
  16.           
  17.         EmployeeBAuserActivityBA =  (EmployeeBA) ctx.getBean("employeeBA");  
  18.           
  19.         EmployeeBEemployeeBE = newEmployeeBE();  
  20.         employeeBE.setName("Naveen");  
  21.           
  22.         userActivityBA.saveUser(employeeBE);  
  23.     }  
  24. }  
Let’s say, you are not throwing any exception in EmpBABean, as it is being called from EmployeeBABean.java.



If you see, two records have been inserted. Now, you change both the method propagations to
@Transactional (propagation = Propagation.REQUIRED) and execute the application.


Two more new records have been inserted.

Now, throw the error in EmpBABean.java and run the application.






No new record has been created because there is an error in inner BA class which causes the whole transaction to be rolled back there. And, no record has been persisted to database.

Now, change the propagation to REQUIRED_NEW and throw the exception and run the application.



If you observe, a new record with id 63 has been created. This is from Outer Business Activity/DAO class EmployeeBABean.java. As the inner BA method has thrown some exception, its data has not been committed to the database. But, the outer BA method is propagated with REQUIRED_NEW, so its data is persisted to database.

Conclusion

These spring transaction attributes play a major role depending on the requirement. Sometimes, there may be cases where irrespective of other entity persistence, the current entity needs to persist. In that case, REQUIRED_NEW is very useful. But, this is a very rare case as it causes data inconsistency. In general, REQUIRED is used for transaction.

Everything shared by java web development experts in this post is according to their practice and experience.

You can share your thoughts and experience with other readers through the comments. Ask questions directly from experts and get response.

Up Next
    Ebook Download
    View all
    Learn
    View all