Tuesday, January 19, 2010

Spring Transaction Part 1 : Using Transaction Manager

2 comments

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"?>


















Monday, January 18, 2010

Grails Hello World

0 comments
When I started learning this new technology, I really surprised. I remember how much I struggled when I created my fist web application using Tomcat and JSP. In Grails everything is pretty easy and simple.

I know the application that I am going to explain here is very simple. But I want to share my joy, that’s the only reason I am putting it here. Since it is my first application I won’t like use an IDE.

I wanted to create a web application which can do the CRUD operations on Album details. The Album details include name, artist, release, and copies.

  1. I downloaded the binary ZIP from http://www.grails.org/Download
  2. Extracted the zip to C:
  3. Appended C:\grails-1.1.2\bin" to path variable
  4. Created GRAILS_HOME C:\grails-1.1.2
  5. I have created a new workspace C:\grails for putting all my Grails application.


Now the platform is ready for me. I have to do only the coding.

  1. I have created an application inside C:\grails directory. The command is grails create-app AlbumService
  2. Then moved inside AlbumService app. cd AlbumService
  3. I have created a controller for my Album Services grails create-controller Album. It created the a controller named AlbumController.groovy inside C:\grails\AlbumService\grails-app\controllers



    class AlbumController {

    def index = {
    render "

    Grails Hello World

    "
    }
    }


  4. Next I wanted to know whether my service is up or not. So I edited the AlbumController.I put a Grails Hello World inside the controller.
  5. Now to run the application I executed the command grails run-app from C:\grails\AlbumService
  6. When I tried the url: http://localhost:8080/AlbumService/album yes the welcome page is ready.
  7. Now I wanted to create my Album domain class. grails create-domain-class album
  8. After that I have edited the file Album.groovy inside C:\grails\AlbumService\grails-app\domain as below. Also I have changed the AlbumController groovy to make def scaffold = true

    class AlbumController {
    def scaffold = true
    def index = {
    render "

    Grails Hello World

    "
    }
    }


    class Album {
    String name
    String artist
    Date release
    Integer copies
    static constraints = {
    }
    }

  9. I have executed the grials run-app again and opened the url: http://localhost:8080/AlbumService/album/list. I could see the application there I was able to perform all the CRUD operations!!!