Saturday 28 September 2013

Programmatic Spring Transaction Management With Example





Programmatic and Declarative transaction management

There are two types of transaction management in spring:

  • Programmatic transaction management: This will give us more flexibility but maintaining this is a bit difficult. In this transaction, we have to manage the transaction with the help of programming.


  • Declarative transaction management: It will help to separate the transaction management from the business code. For achieving this we can use annotations or XML based configuration to manage the transactions.


Example to achieve Programmatic transaction management:-

Below are the two tables query, which we need to execute in mysql test database , If you want to change the database name from test to any other then do the change while configuring the datasource in the xml file.

EMPLOYEE_DATA Table

CREATE TABLE EMPLOYEE_DATA(
EMP_ID INT NOT NULL AUTO_INCREMENT,
FIRST_NAME VARCHAR(20) NOT NULL,
LAST_NAME VARCHAR(20) NOT NULL,
SALARY DOUBLE NOT NULL,
PRIMARY KEY (EMP_ID) );

ATTENDENCE_DETAILS Table

CREATE TABLE ATTENDENCE_DETAILS(
EID INT NOT NULL,
NO_OF_LEAVE INT NOT NULL,
NO_OF_WORKING_DAYS INT NOT NULL,JOINING_DATE DATE NOT NULL );

System Requirements:-
  •             Eclipse Editor or any other.
  •            JDK 1.5 or higher(I am using jdk 1.7.0_03)
  •            Spring jars version 2.5.5.
  •            Other related jars.


Required Jars are:-

spring-tx.jar
spring-beans.jar
spring-context.jar
spring-context-support.jar
spring-core.jar
spring-jdbc.jar
spring-orm.jar
commons-logging.jar
commons-collections-3.2.jar
mysql-connector-java-5.0.4-bin.jar

Steps for creating Eclipse java project for implementing spring transaction management:-
  • Create a java project in eclipse and name it as SpringTransactionExample.
  • Create a package in the src folder with the name as com.gaurav.springtransaction.dao.
  • Create a package in the src folder with the name com.gaurav.springtransaction.bean .
  • Create a package in the src folder with the name com.gaurav.springtransaction.mapper.
  • Create a package in the src folder with the name com.gaurav.springtransaction.dao.impl.
  • Create a package in the src folder with the name com.gaurav.springtransaction.caller.
  • Create an XML file and name it as spring-transactionmanagement.xml and place this file in the classpath outside the src folder.
  • Place the below available files source codes in the corresponding packages.
  • Execute the TestSpringTransactionManagement.java by selecting the option Run as Java Application.


EmployeeDAO.java


package com.gaurav.springtransaction.dao;

import java.util.Date;
import java.util.List;

import com.gaurav.springtransaction.bean.EmployeeData;

public interface EmployeeDAO {

      /**
       * This method is used to insert a new record in the employee_data and
       * attendence_details tables.
       */
      public void insertNewRow(String firstName, String lastName, Double salary,
                  Integer no_of_leave, Integer no_of_working_days, Date joining_date);

      /**
       * This method is used to retrieve all the employees records as list
       * employee_data and attendence_details tables.
       */
      public List<EmployeeData> retrieveEmployeeList();
}


EmployeeData.java


package com.gaurav.springtransaction.bean;

import java.util.Date;

public class EmployeeData {
      private int empId;
      private int eid;
      private String firstName;
      private String lastName;
      private double salary;
      private int noOfLeave;
      private int noOfWorkingDays;
      private Date joiningDate;

      /**
       * @return the empId
       */
      public int getEmpId() {
            return empId;
      }

      /**
       * @param empId
       *            the empId to set
       */
      public void setEmpId(int empId) {
            this.empId = empId;
      }

      /**
       * @return the eid
       */
      public int getEid() {
            return eid;
      }

      /**
       * @param eid
       *            the eid to set
       */
      public void setEid(int eid) {
            this.eid = eid;
      }

      /**
       * @return the firstName
       */
      public String getFirstName() {
            return firstName;
      }

      /**
       * @param firstName
       *            the firstName to set
       */
      public void setFirstName(String firstName) {
            this.firstName = firstName;
      }

      /**
       * @return the lastName
       */
      public String getLastName() {
            return lastName;
      }

      /**
       * @param lastName
       *            the lastName to set
       */
      public void setLastName(String lastName) {
            this.lastName = lastName;
      }

      /**
       * @return the salary
       */
      public double getSalary() {
            return salary;
      }

      /**
       * @param salary
       *            the salary to set
       */
      public void setSalary(double salary) {
            this.salary = salary;
      }

      /**
       * @return the noOfLeave
       */
      public int getNoOfLeave() {
            return noOfLeave;
      }

      /**
       * @param noOfLeave
       *            the noOfLeave to set
       */
      public void setNoOfLeave(int noOfLeave) {
            this.noOfLeave = noOfLeave;
      }

      /**
       * @return the noOfWorkingDays
       */
      public int getNoOfWorkingDays() {
            return noOfWorkingDays;
      }

      /**
       * @param noOfWorkingDays
       *            the noOfWorkingDays to set
       */
      public void setNoOfWorkingDays(int noOfWorkingDays) {
            this.noOfWorkingDays = noOfWorkingDays;
      }

      /**
       * @return the joiningDate
       */
      public Date getJoiningDate() {
            return joiningDate;
      }

      /**
       * @param joiningDate
       *            the joiningDate to set
       */
      public void setJoiningDate(Date joiningDate) {
            this.joiningDate = joiningDate;
      }

}

EmployeeAttendenceDetailsMapper.java


package com.gaurav.springtransaction.mapper;

import java.sql.ResultSet;
import java.sql.SQLException;

import org.springframework.jdbc.core.RowMapper;

import com.gaurav.springtransaction.bean.EmployeeData;

public class EmployeeAttendenceDetailsMapper implements RowMapper {
      @Override
      public EmployeeData mapRow(ResultSet rs, int rowNum) throws SQLException {

            EmployeeData employeeData = new EmployeeData();

            employeeData.setEmpId(rs.getInt("EMP_ID"));
            employeeData.setFirstName(rs.getString("FIRST_NAME"));
            employeeData.setLastName(rs.getString("LAST_NAME"));
            employeeData.setSalary(rs.getDouble("SALARY"));

            employeeData.setEid(rs.getInt("EID"));
            employeeData.setNoOfLeave(rs.getInt("NO_OF_LEAVE"));
            employeeData.setNoOfWorkingDays(rs.getInt("NO_OF_WORKING_DAYS"));
            employeeData.setJoiningDate(rs.getDate("JOINING_DATE"));
            return employeeData;
      }
}


EmployeeDAOImpl.java

package com.gaurav.springtransaction.dao.impl;

import java.util.Date;
import java.util.List;

import javax.sql.DataSource;

import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.DefaultTransactionDefinition;

import com.gaurav.springtransaction.bean.EmployeeData;
import com.gaurav.springtransaction.dao.EmployeeDAO;
import com.gaurav.springtransaction.mapper.EmployeeAttendenceDetailsMapper;

public class EmployeeDAOImpl implements EmployeeDAO {
      private JdbcTemplate jdbcTemplate;
      private PlatformTransactionManager transactionManager;

      /**
       * @param DataSource
       *            the DataSource to be inject in jdbcTemplate
       */
      public void setDataSource(DataSource ds) {
            this.jdbcTemplate = new JdbcTemplate(ds);
      }

      /**
       * @param transactionManager
       *            the transactionManager to set
       */
      public void setTransactionManager(
                  PlatformTransactionManager transactionManager) {
            this.transactionManager = transactionManager;
      }

      @Override
      public void insertNewRow(String firstName, String lastName, Double salary,
                  Integer no_of_leave, Integer no_of_working_days, Date joining_date) {

            TransactionDefinition def = new DefaultTransactionDefinition();
            TransactionStatus status = transactionManager.getTransaction(def);

            try {
                  String insertQueryForEmployee = "insert into EMPLOYEE_DATA (FIRST_NAME, LAST_NAME, SALARY) values (?, ?, ?)";

                  Object[] queryParameterForEmployeeQuery = { firstName, lastName,
                              salary };
                  jdbcTemplate.update(insertQueryForEmployee,
                              queryParameterForEmployeeQuery);

                  /**
                   * Get the latest employee id from employee_data table, so that we
                   * can use it for eid in the attendence_details table
                   **/
                  String getMaxIdQuery = "select max(EMP_ID) from EMPLOYEE_DATA";
                  int eid = jdbcTemplate.queryForInt(getMaxIdQuery);

                  String insertQueryForAttendenceDetails = "insert into ATTENDENCE_DETAILS(EID, NO_OF_LEAVE, NO_OF_WORKING_DAYS, JOINING_DATE) "
                              + "values (?, ?, ?, ?)";

                  Object[] queryParameterForAttendenceDetailsQuery = { eid,
                              no_of_leave, no_of_working_days, joining_date };

                  jdbcTemplate.update(insertQueryForAttendenceDetails,
                              queryParameterForAttendenceDetailsQuery);

                  System.out.println("\n");
                  System.out.println("Inserted Query is having First Name = "
                              + firstName + ", Last Name = " + lastName
                              + ", And Joining Date " + joining_date);

                  transactionManager.commit(status);

            } catch (DataAccessException e) {

                  System.out
                              .println("Error occured during record insertion , so needs to rollback");
                  transactionManager.rollback(status);

                  throw e;
            }
            return;
      }

      @Override
      public List<EmployeeData> retrieveEmployeeList() {
            String SQL = "select * from EMPLOYEE_DATA, ATTENDENCE_DETAILS where EMPLOYEE_DATA.EMP_ID = ATTENDENCE_DETAILS.EID";

            @SuppressWarnings("unchecked")
            List<EmployeeData> employeeDataLst = jdbcTemplate.query(SQL,
                        new EmployeeAttendenceDetailsMapper());
            return employeeDataLst;
      }

}

spring-transactionmanagement.xml

<beans xmlns="http://www.springframework.org/schema/beans"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">

      <!-- mysql data source connection -->
      <bean id="dataSource"
            class="org.springframework.jdbc.datasource.DriverManagerDataSource">
            <property name="driverClassName" value="com.mysql.jdbc.Driver" />
            <property name="url" value="jdbc:mysql://localhost:3306/test" />
            <property name="username" value="root" />
            <property name="password" value="root" />
      </bean>

      <!-- Spring TransactionManager Initialization -->
      <bean id="transactionManager"
            class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
            <property name="dataSource" ref="dataSource" />
      </bean>

      <!-- Provding a definition to EmployeeData for getting data source and spring transaction manager-->
      <bean id="employeeDAOImplBean" class="com.gaurav.springtransaction.dao.impl.EmployeeDAOImpl">
            <property name="dataSource" ref="dataSource" />
            <property name="transactionManager" ref="transactionManager" />
      </bean>

</beans>


TestSpringTransactionManagement.java


package com.gaurav.springtransaction.caller;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.List;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.gaurav.springtransaction.bean.EmployeeData;
import com.gaurav.springtransaction.dao.impl.EmployeeDAOImpl;

public class TestSpringTransactionManagement {
      public static void main(String[] args) throws ParseException {
            ApplicationContext context = new ClassPathXmlApplicationContext(
                        "spring-transactionmanagement.xml");

            EmployeeDAOImpl employeeDAOImplBean = (EmployeeDAOImpl) context
                        .getBean("employeeDAOImplBean");

            System.out
                        .println("********** Inserting the Records in the EmployeeData table ********** ");
            int noOfWorkingDays = 22;

            employeeDAOImplBean.insertNewRow("Kumar", "Gaurav", 70000.00, 5,
                        (noOfWorkingDays - 5), (new SimpleDateFormat("yyyy-MM-dd")).parse("2007-05-08"));
            employeeDAOImplBean.insertNewRow("Anurag", "Kumar", 30000.00, 12,
                        (noOfWorkingDays - 12), (new SimpleDateFormat("yyyy-MM-dd")).parse("2009-03-27"));
            employeeDAOImplBean.insertNewRow("Riya", "Saxena", 45000.00, 7,
                        (noOfWorkingDays - 7), (new SimpleDateFormat("yyyy-MM-dd")).parse("2011-12-15"));

            System.out
                        .println("\n********** Retrieving all the employee records **********");
            List<EmployeeData> employeeDataLst = employeeDAOImplBean
                        .retrieveEmployeeList();
            for (EmployeeData employee : employeeDataLst) {
                  System.out.println("\n");
                  System.out.print("Employee ID : " + employee.getEmpId());
                  System.out.print(", First Name : " + employee.getFirstName());
                  System.out.print(", Last Name : " + employee.getLastName());
                  System.out.print(", Salary : " + employee.getSalary());
                  System.out.print(", No of Leave : " + employee.getNoOfLeave());
                  System.out.print(", No of Working Days : "
                              + employee.getNoOfWorkingDays());
                  System.out.print(", Joining Date : " + employee.getJoiningDate());

            }
      }
}

Result:-

Sep 29, 2013 12:22:54 AM org.springframework.context.support.AbstractApplicationContext prepareRefresh
INFO: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@16546ef: display name [org.springframework.context.support.ClassPathXmlApplicationContext@16546ef]; startup date [Sun Sep 29 00:22:54 IST 2013]; root of context hierarchy
Sep 29, 2013 12:22:54 AM org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
INFO: Loading XML bean definitions from class path resource [spring-transactionmanagement.xml]
Sep 29, 2013 12:22:54 AM org.springframework.context.support.AbstractApplicationContext obtainFreshBeanFactory
INFO: Bean factory for application context [org.springframework.context.support.ClassPathXmlApplicationContext@16546ef]: org.springframework.beans.factory.support.DefaultListableBeanFactory@a353ed
Sep 29, 2013 12:22:54 AM org.springframework.beans.factory.support.DefaultListableBeanFactory preInstantiateSingletons
INFO: Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@a353ed: defining beans [dataSource,transactionManager,employeeDAOImplBean]; root of factory hierarchy
Sep 29, 2013 12:22:54 AM org.springframework.jdbc.datasource.DriverManagerDataSource setDriverClassName
INFO: Loaded JDBC driver: com.mysql.jdbc.Driver
********** Inserting the Records in the EmployeeData table **********


Inserted Query is having First Name = Kumar, Last Name = Gaurav, And Joining Date Tue May 08 00:00:00 IST 2007


Inserted Query is having First Name = Anurag, Last Name = Kumar, And Joining Date Fri Mar 27 00:00:00 IST 2009


Inserted Query is having First Name = Riya, Last Name = Sexena, And Joining Date Thu Dec 15 00:00:00 IST 2011

********** Retrieving all the employee records **********


Employee ID : 1, First Name : Kumar, Last Name : Gaurav, Salary : 70000.0, No of Leave : 5, No of Working Days : 17, Joining Date : 2007-05-08

Employee ID : 2, First Name : Anurag, Last Name : Kumar, Salary : 30000.0, No of Leave : 12, No of Working Days : 10, Joining Date : 2009-03-27

Employee ID : 3, First Name : Riya, Last Name : Saxena, Salary : 45000.0, No of Leave : 7, No of Working Days : 15, Joining Date : 2011-12-15


Below is the data availability status in the corresponding tables after successful program execution:-

EMPLOYEE_DATA





ATTENDENCE_DETAILS