Spring AOP for Database Transaction
August 01, 2012
Spring AOP is Aspect Oriented programming. Same type of Aspect can be found in multiple classes in our application. So to handle that aspect we can make a separate method in a separate class that will be implemented and will run for all classes for the configured aspect. Spring do that by creating proxy class. Spring AOP is based on proxy pattern. We can achieve AOP just by setting some configuration in XML or also can be achieved by creating a class using annotation. Spring AOP can be used for many purpose like logging, pre or post task for a method and Database transaction etc. We will see how to use Spring AOP for database transaction. To learn better first find the some keywords used in AOP.
AOP Terminology
Aspect: Like trasaction management that cuts accross multiple classes.Join point: Joint points are execution of a program like execution of any method.
Advice: Advive is an action at any join point by an aspect.
Pointcut: Pointcut is a predicate that matches join points.
Using AOP for Database Transaction
In database transaction, data integrity is very important. It means if there are more than one insert or update, either every transaction should be successful or every transaction should be rollbacked. If it does not happen, data integrity is lost. To handle this transaction, Spring AOP works best.Configuration for AOP for Database Transaction
Person.java
package com.concretstudy.persistence;
import java.io.Serializable;
import javax.persistence.Entity;
import javax.persistence.Id;
@Entity
public class Person implements Serializable {
private static final long serialVersionUID = 1L;
@Id
private int id;
private String name;
private int age;
public Person(){ }
public Person(int id,String name, int age){
this.id=id;
this.name=name;
this.age=age;
}
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 int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
package com.concretestudy.dao;
public interface ConcreteDao {
public void save();
}
package com.concretestudy.dao;
import org.springframework.orm.hibernate3.HibernateTemplate;
import com.concretstudy.persistence.Person;
public class ConcreteDaoImpl implements ConcreteDao {
private HibernateTemplate hibernateTemplate;
public void setHibernateTemplate(HibernateTemplate hibernateTemplate) {
this.hibernateTemplate = hibernateTemplate;
}
public void save(){
Person p1= new Person(1,"rakesh",25);
hibernateTemplate.save(p1);
Person p2= new Person(2,"mahesh",30);
hibernateTemplate.save(p2);
}
}
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<property name="hibernate.connection.url">
jdbc:mysql://localhost:3306/concretestudy</property>
<property name="hibernate.connection.username">root</property>
<property name="hibernate.connection.password"></property>
<property name="hibernate.connection.pool_size">10</property>
<property name="show_sql">true</property>
<property name="dialect">org.hibernate.dialect.MySQLDialect</property>
<property name="hibernate.hbm2ddl.auto">update</property>
<mapping class="com.concretstudy.persistence.Person"/>
</session-factory>
</hibernate-configuration>
<?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:aop="http://www.springframework.org/schema/aop" 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/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd"> <bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean"> <property name="configLocation" ><value>hibernate.cfg.xml</value></property> </bean> <bean id="hibernateTemplate" class="org.springframework.orm.hibernate3.HibernateTemplate"> <property name="sessionFactory"> <ref bean="sessionFactory" /> </property> </bean> <bean id="concreteDao" class="com.concretestudy.dao.ConcreteDaoImpl"> <property name="hibernateTemplate"> <ref bean="hibernateTemplate" /> </property> </bean> <aop:config> <aop:pointcut id="dbOperation" expression="execution(* com.concretestudy.dao.ConcreteDaoImpl.*(..))" /> <aop:advisor advice-ref="txAdvice" pointcut-ref="dbOperation" /> </aop:config> <tx:advice id="txAdvice" transaction-manager="transactionManager" > <tx:attributes> <tx:method name="get*" read-only="true" isolation="READ_COMMITTED"/> <tx:method name="*" propagation="REQUIRED" isolation="DEFAULT" read-only="false" timeout="-1" /> </tx:attributes> </tx:advice> <bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager"> <property name="sessionFactory" ref="sessionFactory" /> </bean> </beans>
1. Configure transactionManager: sessionFactory is needed to configure transaction manager.
2. Configure advice: method name pattern are defined that will be considered for database transaction and also configure propagation.
3. Configure pointcut : advice is referred to pointcut.
4. To set the methods for Spring AOP, expression is set to class level. As execution(* com.concretestudy.dao.ConcreteDaoImpl.*(..)). By setting this all methods is covered for Spring AOP fro that class.
Run Spring AOP DB Transaction
AppRun.java
package com.concretstudy;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.concretestudy.dao.ConcreteDao;
public class AppRun {
public static void main(String... args) {
ApplicationContext context = new ClassPathXmlApplicationContext("application-context.xml");
ConcreteDao cd=(ConcreteDao) context.getBean("concreteDao");
cd.save();
}
}
Scenario for rollback in AOP DB transaction
Change the save method in ConcreteDaoImpl.java. We have to change in the way that it should produce error. In case of error, expectation from Spring AOP is that complete transaction in save method must rollback. To produce error, make Id same for both the person. And run AppRun.java.
public void save(){
Person p1= new Person(1,"rakesh",25);
hibernateTemplate.save(p1);
Person p2= new Person(1,"mahesh",30);
hibernateTemplate.save(p2);
}



