Monday, October 15, 2018

Spring Transaction example


Many times we need to implements programitically Transaction to adhere to ACID=Atomicity, consistance, Isolation and Durability.
JAVA comes with JTA=Java transection API where in we are using explicitly begin and end key word to start and end the DB trasactions.
If we are using Spring Frame work it provide inbuild Transaction SPI with spring-tx.*.*.jar. We just need to add this jar in our class path and can use their api to achieve ACID for our application.
below is the code
1-POM.xml
<!--project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<!--modelVersion>4.0.0<!--/modelVersion>
<!--groupId>org.springframework.samples<!--/groupId>
<!--artifactId>SpringJDBCTransactionManagement<!--/artifactId>
<!--version>0.0.1-SNAPSHOT<!--/version>
<!--properties>
<!--!-- Generic properties -->
<!--java.version>1.7<!--/java.version>
<!--project.build.sourceEncoding>UTF-8<!--/project.build.sourceEncoding>
<!--project.reporting.outputEncoding>UTF-8<!--/project.reporting.outputEncoding>
<!--!-- Spring -->
<!--spring-framework.version>4.0.2.RELEASE<!--/spring-framework.version>
<!--!-- Logging -->
<!--logback.version>1.0.13<!--/logback.version>
<!--slf4j.version>1.7.5<!--/slf4j.version>
<!--!-- Test -->
<!--junit.version>4.11<!--/junit.version>
<!--maven.compiler.source>1.6<!--/maven.compiler.source>
<!--maven.compiler.target>1.6<!--/maven.compiler.target>

<!--/properties>
<!--dependencies>
<!--!-- Spring and Transactions -->
<!--dependency>
<!--groupId>org.springframework<!--/groupId>
<!--artifactId>spring-context<!--/artifactId>
<!--version>${spring-framework.version}<!--/version>
<!--/dependency>
<!--dependency>
<!--groupId>org.springframework<!--/groupId>
<!--artifactId>spring-tx<!--/artifactId>
<!--version>${spring-framework.version}<!--/version>
<!--/dependency>
<!--!-- Spring JDBC and MySQL Driver -->
<!--dependency>
<!--groupId>org.springframework<!--/groupId>
<!--artifactId>spring-jdbc<!--/artifactId>
<!--version>${spring-framework.version}<!--/version>
<!--/dependency>
<!--dependency>
<!--groupId>mysql<!--/groupId>
<!--artifactId>mysql-connector-java<!--/artifactId>
<!--version>5.0.5<!--/version>
<!--/dependency>
<!--!-- Logging with SLF4J & LogBack -->
<!--dependency>
<!--groupId>org.slf4j<!--/groupId>
<!--artifactId>slf4j-api<!--/artifactId>
<!--version>${slf4j.version}<!--/version>
<!--scope>compile<!--/scope>
<!--/dependency>
<!--dependency>
<!--groupId>ch.qos.logback<!--/groupId>
<!--artifactId>logback-classic<!--/artifactId>
<!--version>${logback.version}<!--/version>
<!--scope>runtime<!--/scope>
<!--/dependency>
<!--!-- Test Artifacts -->
<!--dependency>
<!--groupId>org.springframework<!--/groupId>
<!--artifactId>spring-test<!--/artifactId>
<!--version>${spring-framework.version}<!--/version>
<!--scope>test<!--/scope>
<!--/dependency>
<!--dependency>
<!--groupId>junit<!--/groupId>
<!--artifactId>junit<!--/artifactId>
<!--version>${junit.version}<!--/version>
<!--scope>test<!--/scope>
<!--/dependency>
<!--/dependencies>
<!--/project>
Note:- IF while running the project you get an error Source option 5 is no longer supported. Use 6 or later. please add below line inside properties
<!--maven.compiler.source>1.6</maven.compiler.source>
<!--maven.compiler.target>1.6</maven.compiler.target>
2- spring.xml
<!--?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"
xmlns:tx="http://www.springframework.org/schema/tx"
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-4.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd">
<!--!-- Enable Annotation based Declarative Transaction Management -->
<!--tx:annotation-driven proxy-target-class="true"
transaction-manager="transactionManager" />
<!--!-- Creating TransactionManager Bean, since JDBC we are creating of type
DataSourceTransactionManager -->
<!--bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!--property name="dataSource" ref="dataSource" />
<!--/bean>

<!--!-- MySQL DB DataSource -->
<!--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/vscrum" />
<!--property name="username" value="siddhu" />
<!--property name="password" value="siddhu" />
<!--/bean>
<!--bean id="siddhuDAO" class="com.siddhu.dao.SiddhuDAOImpl">
<!--property name="dataSource" ref="dataSource"><!--/property>
<!--/bean>
<!--bean id="siddhuManager" class="com.siddhu.service.SiddhuManagerImpl">
<!--property name="siddhuDAO" ref="siddhuDAO"><!--/property>
<!--/bean>
<!--/beans>
3-MainTransaction
package com.siddhu.main;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.siddhu.model.AddressInfo;
import com.siddhu.model.CustomerInfo;
import com.siddhu.service.SiddhuManager;
import com.siddhu.service.SiddhuManagerImpl;
public class MainTransaction {
public static void main(String[] args) {
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext(
"spring.xml");
SiddhuManager siddhuManager = ctx.getBean("siddhuManager",
SiddhuManagerImpl.class);
CustomerInfo cust = createCustomer();
siddhuManager.createCustomer(cust);
ctx.close();
}
private static CustomerInfo createCustomer() {
CustomerInfo customerInfo = new CustomerInfo();
customerInfo.setId(1);
customerInfo.setName("Siddhu");
AddressInfo addressInfo = new AddressInfo();
addressInfo.setId(1);
// trying to save proper value in DB.
addressInfo.setAddress("Address1");
// trying to save proper value in DB.
//addressInfo.setAddress("BIG Address 11111111111111111111111111111111111111111111111111111");
customerInfo.setAddress(addressInfo);
return customerInfo;
}
}
4- SiddhuDAO
package com.siddhu.dao;
import com.siddhu.model.CustomerInfo;
public interface SiddhuDAO {
public void create(CustomerInfo customer);
}
5- SiddhuDAOImpl
package com.siddhu.dao;
import javax.sql.DataSource;
import org.springframework.jdbc.core.JdbcTemplate;
import com.siddhu.model.CustomerInfo;
public class SiddhuDAOImpl implements SiddhuDAO {
private DataSource dataSource;
public void setDataSource(DataSource dataSource) {
this.dataSource = dataSource;
}
@Override
public void create(CustomerInfo customer) {
String queryCustomer = "insert into CustomerInfo (id, name) values (?,?)";
String queryAddress = "insert into AddressInfo (id, address) values (?,?)";
JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
jdbcTemplate.update(queryCustomer, new Object[] { customer.getId(),
customer.getName() });
System.out.println("Inserted into Customer Table Successfully");
jdbcTemplate.update(queryAddress, new Object[] { customer.getId(),
customer.getAddress().getAddress()});
System.out.println("Inserted into Address Table Successfully");
}
}

6- AddressInfo
package com.siddhu.model;
public class AddressInfo {
private int id;
private String address;


public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}


}
7- CustomerInfo
package com.siddhu.model;
public class CustomerInfo {
private int id;
private String name;
private AddressInfo address;

public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public AddressInfo getAddress() {
return address;
}
public void setAddress(AddressInfo address) {
this.address = address;
}

}
8- SiddhuManager
package com.siddhu.service;
import com.siddhu.model.CustomerInfo;
public interface SiddhuManager {

public void createCustomer(CustomerInfo custInfo);
}
9- SiddhuManagerImpl
package com.siddhu.service;
import org.springframework.transaction.annotation.Transactional;
import com.siddhu.dao.SiddhuDAO;
import com.siddhu.model.CustomerInfo;
public class SiddhuManagerImpl implements SiddhuManager {
private SiddhuDAO siddhuDAO;
public void setSiddhuDAO(SiddhuDAO siddhuDAO) {
this.siddhuDAO = siddhuDAO;
}
@Override
@Transactional
public void createCustomer(CustomerInfo custInfo) {
siddhuDAO.create(custInfo);
}
}

Now lets try to understand how the flow goes
MainTransaction is our main class. First by using Spring context we load our spring.xml and try to get the singleton bean with name siddhuManager i.e. SiddhuManager
Then we load/fill data inside our model class CustomerInfo and AddressInfo
After that we call createCustomer method of our bean class SiddhuManagerImpl.
Finally this createCustomer method call our *DAOimpl class to insert the data in two table i.e. CustomerInfo and AddressInfo.
Step 1:- First we will insert normal data and will check if the data is inserted into both the table properly.
Note: I am using MySQL as DB if you are using Oracle please make necessary changes in spring.xml

Image1
Check both the table and we will find 1 row inserted into both the table successfully
Now lets try to run the main method with large value of address i..e greater than 45 character. This will fail in inserting the data in AddressInfo table and due to implementation of Transaction it will also roll back CustomerInfo table data.
Image2
No data is inserted into AddressInfo and CustomerInfo table.
Project Structure
Image3
Note:- Through this example we will also understand how the flow work here for dependency injections
1- When we create the instance of SiddhuManagerImpl using spring it will call internally its setter method as per the property siddhuDAO to create new instace of beanid as name siddhuDAO.. which further internally called bean with id dataSource used to connect proper datasource.

No comments: