Transactions Approaches
Spring Framework supports Transactions in two ways.
- Programmatic Approach
- Declarative Approach
1. Programmatic Approach
In Programmatic Approach of transactions, we have to declare the transaction and we have to perform transactions commit or rollback operations explicitly by using JAVA code.
In Programmatic approach if we want to provide transactions then we have to use the following predefined Library.
1. Transaction Manager
The main intention of TransactionManager is is able to define a Transaction Strategy in spring application.
Spring Framework has provided Transaction manager in the form of a predefined interfaces
org.springframework.jdbc.datasource.DataSourceTransactionManager org.springframework.transaction.PlatformTransactionManager org.springframework.orm.hibernate4.HibernateTransactionManager org.springframework.transaction.jta.JtaTransactionManager
In Spring Transaction based applicatins , We must configure either of the above TransactionManager in configuration file and we must inject TransactionManager in DAO implementation class.
DataSourceTransactionManager includes the following methods to manage transaction.
public TransactionStatus getTransaction(TransactionDefinition tx_Def) public void commit(TransactionStatus tx_Status) public void rollback(TransactionStatus tx_Status)
2. TransactionDefinition
org.springframework.transaction.TransactionDefinition is able to specify ISOLATION levels, Propagation behaviours, Transactions Time out and Transactions Read Only status etc.
TransactionDefinition includes the following Constants to manage Transactions ISOLATION Levels in Spring applications.
- ISOLATION_READ_UNCOMMITTED
- ISOLATION_READ_COMMITTED
- ISOLATION_REPEATABLE_READ
- ISOLATION_SERIALIZABLE
TransactionDefinition includes the following Constants to manage Transactions Propagation Behaviors in Spring applications.
- PROPAGATION_REQUIRED
- PROPAGATION_REQUIRES_NEW
- PROPAGATION_SUPPORTS
- PROPAGATION_NOT_SUPPORTED
- PROPAGATION_MANDATORY
- PROPAGATION_NESTED
- PROPAGATION_NEVER
3. TransactionStatus
org.springframework.transaction.TransactionStatus interface provides a simple way for transactional code to control transaction execution and query transaction status. TransactionStatus includes the following methods to manage Transactions in Spring applications.
public boolean isNewTransaction() boolean hasSavepoint() public void setRollbackOnly() public boolean isRollbackOnly() public void flush() public boolean isCompleted()
E.g
package com.ashok.spring.transactions.programmatic.dao; /** * * @author ashok.mariyala * */ public interface TransactionDao { public String transferFunds(String fromAccount, String toAccount, int transferAmt); }
package com.ashok.spring.transactions.programmatic.dao; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.datasource.DataSourceTransactionManager; import org.springframework.transaction.TransactionDefinition; import org.springframework.transaction.TransactionStatus; import org.springframework.transaction.support.DefaultTransactionDefinition; /** * * @author ashok.mariyala * */ public class TransactionDaoImpl implements TransactionDao { private JdbcTemplate jdbcTemplate; private DataSourceTransactionManager transactionManager; public void setJdbcTemplate(JdbcTemplate jdbcTemplate) { this.jdbcTemplate = jdbcTemplate; } public void setTransactionManager(DataSourceTransactionManager transactionManager) { this.transactionManager = transactionManager; } @Override public String transferFunds(String fromAccount, String toAccount, int transferAmt) { String status = ""; TransactionDefinition txDef = new DefaultTransactionDefinition(); TransactionStatus txStatus = transactionManager.getTransaction(txDef); try { withdraw(fromAccount, transferAmt); deposit(toAccount, transferAmt); transactionManager.commit(txStatus); status = "Transaction Success"; } catch (Exception e) { transactionManager.rollback(txStatus); status = "Transaction Failure"; e.printStackTrace(); } return status; } private void deposit(String account, int depAmt) { jdbcTemplate.execute("update account set BALANCE = BALANCE + " + depAmt + " where ACCNO = '" + account + "'"); } private void withdraw(String account, int wdAmt) { jdbcTemplate.execute("update account set BALANCE = BALANCE - " + wdAmt + " where ACCNO = '" + account + "'"); } }
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <property name="driverClassName" value="com.mysql.cj.jdbc.Driver" /> <property name="url" value="jdbc:mysql://localhost:3306/account" /> <property name="username" value="root" /> <property name="password" value="ashok" /> </bean> <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> <property name="dataSource" ref="dataSource" /> </bean> <bean id="transactionDao" class="com.ashok.spring.transactions.programmatic.dao.TransactionDaoImpl"> <property name="jdbcTemplate" ref="jdbcTemplate" /> <property name="transactionManager" ref="transactionManager" /> </bean> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource" /> </bean> </beans>
package com.ashok.spring.transactions.programmatic; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import com.ashok.spring.transactions.programmatic.dao.TransactionDao; /** * * @author ashok.mariyala * */ public class TestProgrammaticTransaction { public static void main(String[] args) { String configFile = "/com/ashok/spring/transactions/programmatic/applicationContext.xml"; ApplicationContext context = new ClassPathXmlApplicationContext(configFile); TransactionDao txDao = (TransactionDao)context.getBean("transactionDao"); String status = txDao.transferFunds("123456789", "987654321", 5000); System.out.println(status); } }
Drawbacks with Transactions Programmatic Approach
- Programmatic Approach is suggestible when we have less no of operations in Transactions, it is not suggestible when we have more no of operations in Transactions.
- Programmatic Approach is somewhat tightly coupled approach, because, it includes both Business logic and Transactions service code as a single unit.
- Programmatic approach is not convenient to use in enterprise Applications.
2. Declarative Approach
In Declarative approach, we will separate Transaction Service code and Business Logic in Spring applications, so that, we are able to get loosely coupled design in Spring applications.
Declarative approach is suggestible when we have more no of operations in Transactions. Declarative approach is not convenient to use in enterprise Applications because of AOP. There are two ways to provide Transaction management in declarative approach.
- Using Transactions Namespace Tags with AOP implementation
- Using Annotations.
1. Using Transactions Namespace Tags with AOP implementation
To manage Transactions in declarative approach, Spring Transaction module has provided the following AOP implemented tags.
1. <tx:advice>
It represents Transaction Advice; it is the implementation of Transaction Service.
2. <tx:attributes>
It will take Transactional methods in order to apply Isolation levels and Propagation behaviors etc. by using <tx:method> tag.
3. <tx:method>
It will define Transactional method and its propagation Behaviors, Isolation levels, Timeout statuses etc.
2. Using Annotations
This approach is very simple to use for transactions in Spring applications. In this approach, we will use @Transactional annotation just before the transactional methods in DAO implementation classes, but, to use this annotation we must activate @Transactional annotation in Spring configuration file by using the following tag.
<tx:annotation-driven transaction-manager="transactionManager"/>
E.g
package com.ashok.spring.transactions.annotations.dao; /** * * @author ashok.mariyala * */ public interface TransactionDao { public String transferFunds(String fromAccount, String toAccount, int transferAmt); }
package com.ashok.spring.transactions.annotations.dao; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.transaction.annotation.Transactional; /** * * @author ashok.mariyala * */ public class TransactionDaoImpl implements TransactionDao { private JdbcTemplate jdbcTemplate; public void setJdbcTemplate(JdbcTemplate jdbcTemplate) { this.jdbcTemplate = jdbcTemplate; } @Transactional @Override public String transferFunds(String fromAccount, String toAccount, int transferAmt) { String status = ""; int val1 = jdbcTemplate.update("update account set BALANCE = BALANCE - " + transferAmt + " where ACCNO = '" + fromAccount + "'"); int val2 = jdbcTemplate.update("update account set BALANCE = BALANCE + " + transferAmt + " where ACCNO = '" + toAccount + "'"); if (val1 == 1 && val2 == 1) { status = "Transaction Success"; } else { status = "Transaction Failure"; } return status; } }
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <property name="driverClassName" value="com.mysql.cj.jdbc.Driver" /> <property name="url" value="jdbc:mysql://localhost:3306/account" /> <property name="username" value="root" /> <property name="password" value="ashok" /> </bean> <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> <property name="dataSource" ref="dataSource" /> </bean> <bean id="transactionDao" class="com.ashok.spring.transactions.programmatic.dao.TransactionDaoImpl"> <property name="jdbcTemplate" ref="jdbcTemplate" /> </bean> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource" /> </bean> </beans>
package com.ashok.spring.transactions.annotations; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import com.ashok.spring.transactions.programmatic.dao.TransactionDao; /** * * @author ashok.mariyala * */ public class TestProgrammaticTransaction { public static void main(String[] args) { String configFile = "/com/ashok/spring/transactions/annotations/applicationContext.xml"; ApplicationContext context = new ClassPathXmlApplicationContext(configFile); TransactionDao txDao = (TransactionDao)context.getBean("transactionDao"); String status = txDao.transferFunds("123456789", "987654321", 5000); System.out.println(status); } }