Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to rollback Spring Transaction when an Exception is thrown

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()

like image 898
arvin_codeHunk Avatar asked May 07 '13 14:05

arvin_codeHunk


People also ask

Does transaction rollback on exception?

Note that by default, rollback happens for runtime, unchecked exceptions only. The checked exception does not trigger a rollback of the transaction.

How do you handle transaction rollback exception?

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.

How do I rollback a transaction in Spring?

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.

Does Spring rollback on checked exception?

(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.


2 Answers

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.

like image 182
JB Nizet Avatar answered Nov 15 '22 05:11

JB Nizet


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();
}
like image 31
Sachin Gorade Avatar answered Nov 15 '22 04:11

Sachin Gorade