Tuesday, January 19, 2010

Spring Transaction Part 1 : Using Transaction Manager

This time I wanted to explore Spring Transaction Management. There are two types of transaction implementations




1. Programmatic

2. Declarative



I would like to try the programmatic one first. The example I have used is the classic account transfer. For that first I have created a table in PostgreSQL DB.



1. Table Creation



CREATE TABLE account_table

( account_number character varying(20) NOT NULL, owner_name character varying(50) NOT NULL, balance double precision NOT NULL, CONSTRAINT account_table_pk PRIMARY KEY (account_number) )

My account_table has three fields:

1. account_number

2. owner_name

3. balance

with account_number as the primary key.

Also I have inserted some data into the table using the insert commands.



2. Table Bean



Next I have created the java bean corresponding to account_table



public class Account {
@Override
public String toString() {
return "Account [accountNumber=" + accountNumber + ", balance="+ balance + ", name=" + name + "]";
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAccountNumber() {
return accountNumber;
}
public void setAccountNumber(String accountNumber) {
this.accountNumber = accountNumber;
}
public double getBalance() {
return balance;
}
public void setBalance(double balance) {
this.balance = balance;
}
private String accountNumber;
private double balance;
private String name;
}


3. DAO Interface.



I have created the dao with two operations: update & findByPrimaryKey





public interface AccountDao {
public int update(Account account);
public Account findByPrimaryKey(String id);
}




4. Dao Implementation.




package com.binarynovae.spring.trans;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;

import org.springframework.jdbc.core.simple.ParameterizedRowMapper;
import org.springframework.jdbc.core.support.JdbcDaoSupport;

public class AccountDaoImpl extends JdbcDaoSupport implements AccountDao {

@Override
public int update(Account account) {
String sql = "update account_table set owner_name = ?, balance= ? where account_number = ?";
Object[] args = {account.getName(),account.getBalance(),account.getAccountNumber()};
int status=this.getJdbcTemplate().update(sql, args);
return status;
}

@Override
public Account findByPrimaryKey(String id) {
String sql = "select account_number,balance,owner_name from account_table where account_number = ?";
Object[] args = {id};
List<?> accountList = this.getJdbcTemplate().query(sql, args, new ParameterizedRowMapper(){
public Account mapRow(ResultSet rs, int rowNum)
throws SQLException {
Account account = new Account();
account.setAccountNumber(rs.getString("account_number"));
account.setBalance(rs.getDouble("balance"));
account.setName(rs.getString("owner_name"));
return account;
}
});
if(accountList!=null && accountList.size()>0){
return (Account) accountList.get(0);
}
else{
return null;
}
}

}


5. Service Method



The method which implements the transaction. First I wanted to know if I am not putting the transaction what will happen. Here the class is having transfer method, which will accept from account number, to account number and the amount needs to be transferred. I have put a condition for throwing an exception after deduction the amount from the source account but before adding to the target account. So here if we are entering an amount, which is multiple of 1000, will throw the exception and the transaction become inconsistent.




package com.binarynovae.spring.trans;

import java.util.Scanner;

import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.DefaultTransactionDefinition;

public class AccountServiceUsingTxManager {

public AccountDao getAccountDao() {
return accountDao;
}

public void setAccountDao(AccountDao accountDao) {
this.accountDao = accountDao;
}

private AccountDao accountDao;
public PlatformTransactionManager getTxManager() {
return txManager;
}

public void setTxManager(PlatformTransactionManager txManager) {
this.txManager = txManager;
}

private PlatformTransactionManager txManager;
/**
* @param args
*/
public static void main(String[] args) {
BeanFactory BeanFactory = new ClassPathXmlApplicationContext("ApplicationContext.xml");
AccountServiceUsingTxManager accountService = (AccountServiceUsingTxManager)BeanFactory.getBean("accountService");
Scanner scanner = new Scanner(System.in);
System.out.println("Source A/c Number: ");
String srcAcNo = scanner.next();
System.out.println("Dest A/c Number: ");
String dstAcNo = scanner.next();
System.out.println("Amount: ");
double amount = scanner.nextDouble();
System.out.println("Before Transaction: ");
accountService.displayAccount(srcAcNo);
accountService.displayAccount(dstAcNo);
accountService.transfer(srcAcNo, dstAcNo, amount);
System.out.println("After Transaction: ");
accountService.displayAccount(srcAcNo);
accountService.displayAccount(dstAcNo);
}

private void displayAccount(String acNo) {
Account ac = accountDao.findByPrimaryKey(acNo);
System.out.println(ac);
}
private boolean breakTx(double amount){
if(amount%1000==0)
return true;
else
return false;
}
public void transfer(String srcAcNo, String dstAcNo, double amount){
Account src = accountDao.findByPrimaryKey(srcAcNo);
Account target = accountDao.findByPrimaryKey(dstAcNo);
src.setBalance(src.getBalance()-amount);
target.setBalance(target.getBalance()+amount);
//TransactionDefinition txDef = new DefaultTransactionDefinition(TransactionDefinition.PROPAGATION_REQUIRED);
//TransactionStatus txStatus = txManager.getTransaction(txDef);
try {
accountDao.update(src);
if(this.breakTx(amount))
throw new RuntimeException();
accountDao.update(target);
//txManager.commit(txStatus);
} catch (Exception e) {
e.printStackTrace();
//txManager.rollback(txStatus);
}
}

}




Now to enable transaction management just uncomment the lines which are commented.



6. Jars required in the classpath.



postgresql-8.4-701.jdbc4.jar


spring-jdbc.jar


spring.jar


commons-logging.jar



6. Application Context file



We can see we are creating the instance of DataSourceTransactionManager and injecting into AccountServiceUsingTxManager instance.



<?xml version="1.0" encoding="UTF-8"?>


















2 comments:

Anonymous said...

In the meantime, I am not in this post agreeing, nor disagreeing, with any of the questions, your meal does not comply with the Paleo Diet
is when it comes to the total cholesterol values.

Also visit my homepage; natural weight loss

Anonymous said...

Organic listing means to have a team of center experts lies the island of strategists who work with" content" instead of links.
Optimization, as a freelance writer, need to know to start optimizing websites
on your own keywords using Google search with
and without Page Wash.

Look at my weblog - miami search engine optimization

Post a Comment