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


packagecom.gaurav.springtransaction.dao;

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

importcom.gaurav.springtransaction.bean.EmployeeData;

public interfaceEmployeeDAO {

      /**
       * This method is used to insert a new record in the employee_data and
       * attendence_details tables.
       */
      publicvoid 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.
       */
      publicList<EmployeeData> retrieveEmployeeList();
}


EmployeeData.java


packagecom.gaurav.springtransaction.bean;

import java.util.Date;

public class EmployeeData {
      private int empId;
      private int eid;
      privateString firstName;
      privateString lastName;
      privatedouble salary;
      privateint noOfLeave;
      privateint noOfWorkingDays;
      privateDate joiningDate;

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

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

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

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

      /**
       * @return the firstName
       */
      publicString getFirstName() {
            returnfirstName;
      }

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

      /**
       * @return the lastName
       */
      publicString getLastName() {
            returnlastName;
      }

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

      /**
       * @return the salary
       */
      publicdouble getSalary() {
            returnsalary;
      }

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

      /**
       * @return the noOfLeave
       */
      publicint getNoOfLeave() {
            returnnoOfLeave;
      }

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

      /**
       * @return the noOfWorkingDays
       */
      publicint getNoOfWorkingDays() {
            returnnoOfWorkingDays;
      }

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

      /**
       * @return the joiningDate
       */
      publicDate getJoiningDate() {
            returnjoiningDate;
      }

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

}

EmployeeAttendenceDetailsMapper.java


packagecom.gaurav.springtransaction.mapper;

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

importorg.springframework.jdbc.core.RowMapper;

importcom.gaurav.springtransaction.bean.EmployeeData;

public class EmployeeAttendenceDetailsMapperimplements RowMapper {
      @Override
      publicEmployeeData 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"));
            returnemployeeData;
      }
}


EmployeeDAOImpl.java

packagecom.gaurav.springtransaction.dao.impl;

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

import javax.sql.DataSource;

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

importcom.gaurav.springtransaction.bean.EmployeeData;
importcom.gaurav.springtransaction.dao.EmployeeDAO;
importcom.gaurav.springtransaction.mapper.EmployeeAttendenceDetailsMapper;

public classEmployeeDAOImpl implements EmployeeDAO {
      privateJdbcTemplate jdbcTemplate;
      privatePlatformTransactionManager transactionManager;

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

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

      @Override
      publicvoid 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";
                  inteid = 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);

                  throwe;
            }
            return;
      }

      @Override
      publicList<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,
                        newEmployeeAttendenceDetailsMapper());
            returnemployeeDataLst;
      }

}

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


packagecom.gaurav.springtransaction.caller;

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

importorg.springframework.context.ApplicationContext;
importorg.springframework.context.support.ClassPathXmlApplicationContext;

importcom.gaurav.springtransaction.bean.EmployeeData;
importcom.gaurav.springtransaction.dao.impl.EmployeeDAOImpl;

public class TestSpringTransactionManagement {
      publicstatic 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 ********** ");
            intnoOfWorkingDays = 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