Recent Posts

Thursday, 8 August 2019

Spring Transaction Management

Transaction Management
     Transaction is a unit of work performed by Front End applications on Back End System.
E.g.
☀ Deposit some amount in an Account.
☀ Withdraw some amount from an Account
☀ Transfer some amount from one account to another account
     In database applications, Every Transaction must follow ACID properties
1. Atomicity: This property will make the Transaction either in SUCCESS state or in FAILURE state. In Database related applications, if we perform all operations then the Transaction is available in SUCCESS State, if we perform none of the operations then the Transaction is available in FAILURE state.
2. Consistency: In database applications, Before the Transaction and After the Transaction Database state must be in stable.
3. Isolation: If we run more than one Transaction on a single Data item then that Transactions are called as "Concurrent Transactions". In Transactions Concurrency, one transaction execution must not give effect to another Transaction, this rule is called as "Isolation" property.
4. Durability: After committing the Transaction, if any failures are coming like Power failure, OS failure etc. after getting the System if we open the transaction then the modifications which we performed during the transaction must be preserved.
    In JDBC, to perform Atomicity property we have to change Connections auto-commit nature and we have to perform either commit() or rollback() at the end of Transaction.
Connection con = DriverManager.getConnection(---);
con.setAutoCommit(false);
try{
   ---instructions-----
   con.commit();
} catch(Exception e){
   e.printStacktrace();
   con.rollback();
}
     In Hibernate applications, if we want to manage Transactions Atomicity property then we have to use the following steps.
1. Declare Transaction Before try.
2. Create Transaction object inside try block.
3. Perform commit() operation at end of Transaction.
4. Perform rollback() operation at catch block.
E.g.
Transaction tx = null;
try{
   -----
   tx = session.beginTransaction();
   ----
   -----
   tx.commit();
} catch(Exception e){
   tx.rollback();
}
     If we execute more than one transaction on a single data item then that transactions are called as Concurrent Transactions. In Transactions concurrency we are able to get the following data consistency problems while executing more than one transaction at a time.
1. Lost Update Problem
2. Dirty Read Problem
3. Non Repeatable Read Problem
4. Phanthom Read Problem

1. Lost Update Problem
     In Transactions concurrency, if one transaction performs updations over the data without commit operation, meanwhile, other transactions perform updations with commit operation then the first transaction updations are lost, this data consistency problem is called as Lost Update problem.
2. Dirty Read Problem
     In Transactions concurrency, if one transaction perform updations over data without performing commit / rollback, meanwhile if other Transaction perform Read operation over the uncommitted data without performing commit/rollback operations, in this context, if first transaction perform Rollback operation then the read operation performed by second transaction is Dirty Read, this problem is called as Dirty Read problem.

3. Non-Repeatable Read Problem
     In Transactions concurrency, one transaction performs continuous read operations to get same results, meanwhile, between two read operations another transaction performs update operation over the same data, in this context, in the next read operation performed by first transaction may not get same repeatable results, this problem is called as Non-Repeatable Read Problem.
4. Phantom Read Problem
     In Transactions concurrency, one transaction perform read operation continuously to get same no of results at each and every read operation , meanwhile, other transactions may perform insert operations between two read operations performed by first transactions, in this context, in the next read operation performed by first transaction may not generate the same no of results, this problem is called as "Panthom Read" Problem, here the extra records inserted by second transaction are called as "Phantom Records".
There are two types of Transactions
1. Local Transaction
2. Global Transaction

1. Local Transaction
     Local transactions are specific to a single transactional resource like a JDBC connection. Local transaction management can be useful in a centralized computing environment where application components and resources are located at a single site, and transaction management only involves a local data manager running on a single machine. Local transactions are easier to be implemented.

2. Global Transaction
     Global transactions can span multiple transactional resources like transaction in a distributed system. Global transaction management is required in a distributed computing environment where all the resources are distributed across multiple systems
     A distributed or a global transaction is executed across multiple systems, and its execution requires coordination between the global transaction management system and all the local data managers of all the involved systems.

Transaction Support in Spring
     Spring provides extensive support for transaction management and help developers to focus more on business logic rather than worrying about the integrity of data in case of any system failures. Spring Transaction Management is providing the following advantages in enterprise applications:
1. Spring Supports Declarative Transaction Management. In this model, Spring uses AOP over the transactional methods to provide data integrity. This is the preferred approach and works in most of the cases.
2. Spring Supports most of the transaction APIs such as JDBC, Hibernate, JPA, JDO, JTA etc. All we need to do is use proper transaction manager implementation class.
E.g.
☀ org.springframework.jdbc.datasource.DriverManagerDataSource for JDBC transaction management
☀ org.springframework.orm.hibernate3.HibernateTransactionManager for Hibernate as ORM tool.
☀ Support for programmatic transaction management by using TransactionTemplate or PlatformTransactionManager implementation.

     To represent ISOLATION levels Spring Framework has provided the following Constants from "org.springframework.transaction .TransactionDefinition".
1. ISOLATION_DEFAULT: It is default isolation level; it will use the underlying database provided default Isolation level.
2. ISOLATION_READ_UNCOMMITTED: It will not resolve any ISOLATION problem, it represents dirty read problem, non-repeatable read problem, phantom read problem.
3. ISOLATION_READ_COMMITTED: It will resolve dirty read problem, but, it will represent non-repeatable read problem and phantom read problem.
4. ISOLATION_REPEATABLE_READ: It will resolve dirty read problem and non-repeatable read problem, but, It will represent phantom read problem.
5. ISOLATION_SERIALIZABLE: It will resolve all ISOLATION problems like dirty reads, non-repeatable read, and phantom read Problems.
     To set the above Isolation level to TransactionTemplate then we have to use the following method.
public void setIsolationLevel(int value)
E.g.
txTemplate.setIsolationLevel(TransactionDefinition.ISOLATION_DEFAULT);

Transaction Attributes
     In Enterprise applications, if a method begins a transaction and access another method, in this context, another method execution is going on the same Transaction or in any new Transaction is completely depending on the Transaction Propagation behavior what we are using.
Spring Framewrk has provided very good suport for Propagation Behavior in the form of the following constants from "org.springframework.transaction .TransactionDefinition".
1. PROPAGATION_REQUIRED
2. PROPAGATION_REQUIRES_NEW
3. PROPAGATION_SUPPORTS
4. PROPAGATION_NOT_SUPPORTED
5. PROPAGATION_MANDATORY
6. PROPAGATION_NEVER
7. PROPAGATION_NESTED
1. PROPAGATION_REQUIRED
     If a method1 is running in a transaction and invokes method2 then method2 will be executed in the same transaction. If method1 is not associated with any Transaction then Container will create new Transaction to execute Method2.
2. PROPAGATION_REQUIRES_NEW
     If a method1 is running in a transaction and invokes method2 then container will suspend the current Transaction temporarily and creates new Transaction for method2. After executing method2 transaction then method1 transaction will continue. If Method1 is not associated with any transaction then container will start a new transaction before starts new method.
3. PROPAGATION_MANDATORY
     If a method1 is running in a transaction and invokes method2 then method2 will be executed in the same transaction. If method1 is not associated with any Transaction then Container will raise an exception like "TransactionThrowsException".
4. PROPAGATION_SUPPORTS
     If a method1 is running in a transaction and invokes method2 then method2 will be executed in the same transaction. If method1 is not associated with any Transaction then Container does not start new Transaction before running method2.
5. PROPAGATION_NOT_SUPPORTED
     If a method1 is running in a transaction and invokes method2 then Container Suspends the Mehod1 transaction before invoking Method2. When Method2 has completed, container resumes Method1 transaction. If Mehod1 is not associated with Transaction then Container does not start new Transaction before executing Method2.
6. PROPAGATION_NEVER
     If a method1 is running in a transaction and invokes method2 then Container throws an Exception like RemoteException. I mthod1 is not associated with any transaction then Container will not start new Transaction for Method2.
7. PROPAGATION_NESTED
     Indicates that the method should be run with in a nested transaction if an existed transaction is in progress.
     To set the above Propagation Behavior to TransactionTemplate then we have to use the following method.
public void setPropagationBehaviour(int value)
E.g.txTemplate.setPropagationBehaviour(TransactionDefinition.PROPAGATION_EQUIRES_NEW);

Transactions Approaches in Spring
     Spring Framework supports Transactions in two ways.
1. Programmatic Approach
2. 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
1. org.springframework.jdbc.datasource.DataSourceTransactionManager
2. org.springframework.transaction.PlatformTransactionManager
3. org.springframework.orm.hibernate4.HibernateTransactionManager
4. 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.
1. public TransactionStatus getTransaction(TransactionDefinition tx_Def)
2. public void commit(TransactionStatus tx_Status)
3. 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.
1. ISOLATION_READ_UNCOMMITTED
2. ISOLATION_READ_COMMITTED
3. ISOLATION_REPEATABLE_READ
4. ISOLATION_SERIALIZABLE
     TransactionDefinition includes the following Constants to manage Transactions Propagation Behaviors in Spring applications.
1. PROPAGATION_REQUIRED
2. PROPAGATION_REQUIRES_NEW
3. PROPAGATION_SUPPORTS
4. PROPAGATION_NOT_SUPPORTED
5. PROPAGATION_MANDATORY
6. PROPAGATION_NESTED
7. 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.
1. public boolean isNewTransaction()
2. boolean hasSavepoint()
3. public void setRollbackOnly()
4. public boolean isRollbackOnly()
5. public void flush()
6. 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
1. 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.
2. Programmatic Approach is somewhat tightly coupled approach, because, it includes both Business logic and Transactions service code as a single unit.
3. Programmatic approach is not convenient to use in enterprise Applications.

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.
1. Using Transactions Namespace Tags with AOP implementation
2. 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 Spriong 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 vy 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); 
   }
}

Next Tutorial : Spring MVC Part 1

Previous Tutorial : Spring ORM

No comments:

Post a Comment