Feeds:
Posts
Comments

Posts Tagged ‘checked exception’

I have been using Spring TX Management for quite sometime until I recently came upon an article describing the common pitfalls that occur in Transaction Strategies. Although many cases were covered, I would like to describe the common one that is seen in most code.

I am going to explain it with the help of a sample example. In the example we shall put together a sample Service which in turn calls a DAO. The service will call two methods from the DAO. It is only a trivial Service-DAO example.

First the DAO class : DAOStep.java


package com.tx.app.dao;

import java.sql.Types;
import java.util.Calendar;

import org.springframework.jdbc.core.namedparam.NamedParameterJdbcDaoSupport;
import org.springframework.jdbc.core.support.JdbcDaoSupport;

public class DAOStep extends  NamedParameterJdbcDaoSupport implements IDAOStep
{
	

	public void updateData(int val1 , int val2) 
	{
	
		final String insertIntoTest = "UPDATE TEST SET VAL1= ? where VAL2= ? ";

		getJdbcTemplate().update(insertIntoTest,
				new Object[]{
							val1,
							val2
							},
				new int[]{
						 Types.INTEGER,
						 Types.INTEGER,
					});

	}
	

	public void insertData(int val1 , int val2) 
	{
		
		
		final String insertIntoTest = "insert into TEST(VAL1,VAL2) values(?,?) ";

		getJdbcTemplate().update(insertIntoTest,
				new Object[]{
							val1,
							val2
							},
				new int[]{
						 Types.INTEGER,
						 Types.INTEGER,
					});

	}
	

}

Next the Service class : ServiceStep.java

package com.tx.app.service;

import com.tx.app.dao.IDAOStep;
import com.tx.app.exception.MyCheckedException;
import com.tx.app.exception.MyRuntimeException;

public class ServiceStep 
{

	private IDAOStep daoStep;
	
	public void doStepRuntimeException()
	{
		daoStep.insertData(2, 2);
		daoStep.updateData(-2, 2);
		throw new MyRuntimeException();

		
	}
	
	public void doStepCheckedException() throws MyCheckedException
	{
		daoStep.insertData(2, 2);
		daoStep.updateData(-2, 2);
		throw new MyCheckedException();

		
	}	

	public IDAOStep getDaoStep() {
		return daoStep;
	}

	public void setDaoStep(IDAOStep daoStep) {
		this.daoStep = daoStep;
	}

	


	
	
}

As you can see the service throws two exceptions, one a checked exception(MyCheckedException) and second a runtime exception (MyRuntimeException).

Next the Runtime Exception class : MyRuntimeException.java

package com.tx.app.exception;

public class MyRuntimeException extends RuntimeException
{

}

Next the Checked Exception class: MyCheckedException.java

package com.tx.app.exception;

public class MyCheckedException extends Exception
{

}

And the main class to bootstrap the application

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.tx.app.dao.IDAOStep;
import com.tx.app.exception.MyCheckedException;
import com.tx.app.service.ServiceStep;


public class Main 

{

	
	
	public static void main(String[] args) throws MyCheckedException 
	{
	
		ApplicationContext context = new ClassPathXmlApplicationContext(new String[]{"context.xml"});
		ServiceStep service = (ServiceStep)context.getBean("serviceStepTX");
		/*Method One*/
		service.doStepRuntimeException();
		/*Method Two*/
		service.doStepCheckedException();
		
		
		
	}
	
	
}

Finally the Spring XML context file : context.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"
		xsi:schemaLocation="http://www.springframework.org/schema/beans
							http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
	

   
    <bean id="faceDataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
   		<property name="driverClass" value="com.mysql.jdbc.Driver"/>
		<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/facedb"/>
		<property name="user" value="root"/>	
		<property name="password" value=""/>	
		<property name="initialPoolSize"><value>3</value></property>		
		<property name="minPoolSize"><value>5</value></property>	
		<property name="acquireIncrement"><value>5</value></property>		
        <property name="acquireRetryAttempts"><value>10</value></property>
        <property name="acquireRetryDelay"><value>1000</value></property>
        <property name="checkoutTimeout"><value>600000</value></property>
        <property name="maxPoolSize"><value>25</value></property>
        <property name="maxStatements"><value>200</value></property>
        <property name="maxStatementsPerConnection"><value>20</value></property>
        <property name="maxIdleTimeExcessConnections"><value>600</value></property>
    </bean>
    
	
	<bean id="daoStep" class="com.tx.app.dao.DAOStep">
		<property name="dataSource" ref="faceDataSource"/>
	</bean>
	
	<bean id="serviceStep" class="com.tx.app.service.ServiceStep">
		<property name="daoStep"  ref="daoStep"/>
	</bean>
	
	<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    	<property name="dataSource" ref="faceDataSource"/>
    </bean>
    

	<bean id="serviceStepTX" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
		<property name="transactionManager" ref="txManager"/>
		<property name="target" ref="serviceStep"/>
		<property name="proxyTargetClass" value="true"/>		
		<property name="transactionAttributes">
			<props>
				<prop key="doStepRuntimeException*">PROPAGATION_REQUIRED</prop>
				<prop key="doStepCheckedException*">PROPAGATION_REQUIRED</prop>				
			</props>
		</property>
	</bean>    
	
    
</beans>

The Table that needs to be there in some database is TEST. I am using MySQL database and following is the script used to create the TEST table

CREATE TABLE TEST
(VAL1 INT,
VAL2 INT) engine=innodb

Question

As you can see the Transaction attribute for the doStepRuntimeException and doStepCheckedException are both PROPAGATION_REQUIRED. What do you think would be the outcome when the Main class is executed once with Method 1 and once with Method 2? Would the records be inserted as well as updated in the database?

Explanation

The answer is follows.

Method 1)
The whole transaction is rolled back as RuntimeException is thrown and the current transaction is Rolled back

Method 2)
The whole transaction is committed as a checked exception (Exception) is thrown and the current transaction is Commited.

The correct way to rollback both the transactions would be to alter the XML file as follows

<bean id="serviceStepTX" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
		<property name="transactionManager" ref="txManager"/>
		<property name="target" ref="serviceStep"/>
		<property name="proxyTargetClass" value="true"/>		
		<property name="transactionAttributes">
			<props>
				<prop key="doStepRuntimeException*">PROPAGATION_REQUIRED,-MyRuntimeException</prop>
				<prop key="doStepCheckedException*">PROPAGATION_REQUIRED,-MyCheckedException</prop>				
			</props>
		</property>
	</bean>  

However, if you want to rollback all checked exceptions you can use -Exception instead of -MyCheckedException. The default behaviour is for Unchecked exception the current transaction is rolled back and for Checked exception the current transaction is commited.

Advertisements

Read Full Post »