I am using spring 3.0.5 and hibernate 3.6. In my project there is a scenario where i have to rollback transaction of any exception in thrown or error occurs. This the sample code, Everything works fine except transaction is not getting rolled back when I throw an Exception but if any exception is thrown such as mysql.IntegrityConstraintException then transaction gets rolled back, why this is not happening in my case?
applicationContext.xml
<bean id="propertyConfigurer"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location" value="classpath:database.properties"/>
</bean>
<bean id="myDataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="${jdbc.driverClassName}" />
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
</bean>
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource" ref="myDataSource" />
<property name="packagesToScan" value="com.alw.imps"/>
<property name="configLocation">
<value>
classpath:hibernate.cfg.xml
</value>
</property>
</bean>
<bean id="stateDao" class="com.alw.imps.dao.StateDaoImpl">
<property name="sessionFactory" ref="sessionFactory"></property>
</bean>
<bean id="stateService" class="com.alw.imps.services.StateService">
<property name="stateDao" ref="stateDao"></property>
<property name="cityDao" ref="cityDao"></property>
<property name="customerDao" ref="customerDao"></property>
</bean>
<bean id="customerDao" class="com.alw.imps.dao.CustomerDaoImpl">
<property name="sessionFactory" ref="sessionFactory"></property>
</bean>
<bean id="cityDao" class="com.alw.imps.dao.CityDaoImpl">
<property name="sessionFactory" ref="sessionFactory"></property>
</bean>
<tx:annotation-driven transaction-manager="transactionManager" />
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<tx:advice id = "txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="*" propagation="REQUIRED" />
</tx:attributes>
</tx:advice>
Service class StateService
@Transactional(rollbackFor={Exception.class})
public class StateService {
private StateDaoImpl stateDao;
private CityDao cityDao;
private CustomerDao customerDao;
public void setCustomerDao(CustomerDao customerDao) {
this.customerDao = customerDao;
}
public void setStateDao(StateDaoImpl stateDao) {
this.stateDao = stateDao;
}
public CityDao getCityDao() {
return cityDao;
}
public void setCityDao(CityDao cityDao) {
this.cityDao = cityDao;
}
public void addState() {
try {
State state=new State();
state.setStateName("Delhi");
stateDao.create(state);
addCity();
addCustomer();
} catch(Exception e) {
e.printStackTrace();
}
}
public void addCity() throws Exception {
City city=new City();
city.setCiytName("Delhi");
city.setStateId(1);
cityDao.create(city);
}
public void addCustomer() throws Exception {
throw new java.lang.Exception();
}
DAO
public class StateDaoImpl extends GenericDaoImpl<State, Integer> implements StateDao {
}
GenericDaoImpl
public class GenericDaoImpl<T,PK extends Serializable> implements GenericDao<T,PK> {
public SessionFactory sessionFactory;
public void setSessionFactory(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
public Session getSession() {
return sessionFactory.getCurrentSession();
}
public PK create(T o) {
Session ss= getSession();
ss.save(o);
return null;
}
hibernate.cfg
<hibernate-configuration>
<session-factory>
<property name="connection.pool_size">1</property>
<property name="dialect">org.hibernate.dialect.MySQLInnoDBDialect</property>
<property name="cache.provider_class">org.hibernate.cache.NoCacheProvider</property>
<property name="show_sql">true</property>
<property name="hbm2ddl.auto">update</property>
<property name="defaultAutoCommit">false</property>
<mapping class="com.alw.imps.pojo.State"/>
<mapping class="com.alw.imps.pojo.City"/>
</session-factory>
</hibernate-configuration>
So as I said my problem is transaction is not getting rollback when i throw an exception of type Exception from method addCustomer()
Note that by default, rollback happens for runtime, unchecked exceptions only. The checked exception does not trigger a rollback of the transaction.
It is thrown under two circumstances: At transaction commit time, if the transaction has been marked for rollback only. In this case, the commit method will roll back the transaction and throw this exception to indicate that the transaction could not be committed.
In this example, we added @Transactional annotation to roll back the transaction if the exception occurred. The above example proves that the @Transactional annotation can roll back the transaction if the exception occurs. Take note, Spring only rolled back on unchecked exceptions by default.
(Errors will also - by default - result in a rollback.) Checked exceptions that are thrown from a transactional method will not result in the transaction being rolled back.
Your transaction is not rollbacked because there is no exception thrown: the addState()
method that you call catches the exception:
public void addState() {
try {
State state=new State();
state.setStateName("Delhi");
stateDao.create(state);
addCity();
addCustomer();
}
catch(Exception e) {
e.printStackTrace();
}
}
So the transactional Spring proxy doesn't see any exception thrown and doesn't rollback the transaction.
It works for exceptions thrown from the DAO because the DAO is itself transactional, so its own transactional proxy detects the exception being thrown by the DAO and marks the transaction for rollback. The exception is then propagated to the service and caught by your code, but the transaction is already marked for rollback at this point.
Your transaction is not getting rolled back because you are not letting Exception to reach to Spring framework, you are catching the exception in your code itself. So instead of
public void addState()
{
try
{
State state=new State();
state.setStateName("Delhi");
stateDao.create(state);
addCity();
addCustomer();
}
catch(Exception e)
{
e.printStackTrace();
}
}
use
public void addState()
{
State state=new State();
state.setStateName("Delhi");
stateDao.create(state);
addCity();
addCustomer();
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With