Search code examples
javahibernatespring-3

Spring @Transaction does not rollback on Exception thrown


I've searched around for this question, there's quite a few of them here on StackOverflow and Google but I can't seem to get anything working for me.

here are my codes Spring config: (I dont use any pointcut - I think I dont need to?)

<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
...
</bean>

<bean id="hibernateSessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
 <property name="dataSource" ref="dataSource" />
 ...
</bean>

<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
        <property name="sessionFactory" ref="hibernateSessionFactory"/>
</bean>
<tx:annotation-driven transaction-manager="transactionManager"/>

I have a Service class:

@Service
public class ServiceImpl implements ServiceInterface 
{
    /**
     * Injected session factory
     */
    @Autowired(required=true)
    private SessionFactory sessionFactory;

    @Autowired(required=true)
    private Dao myDao;

    /**
     * {@inheritDoc}
     */
    @Transactional(rollbackFor=Exception.class, propagation=Propagation.REQUIRED)
    public void scheduleBlast(BlastParameters blastParameters) throws ServiceException 
    {
        ... do bunch of stuff ..
        myDao.persist(entity)

        if(true)
            throw new ServiceException("random error")
    }

    .. setter methods and other stuff ..
}

and a Dao class:

public class DaoImpl implements DaoInterface
{
    @Autowired(required=true)
    private SessionFactory sessionFactory

    /**
     * {@inheritDoc}
     */
    @Transactional(propagation=Propagation.MANDATORY)
    public void persist(Entity e) throws DaoException
    {
        try
        {
            sessionFactory.getCurrentSession().persist(e);
        }
        catch(Exception ex)
        {
            throw new DaoException(ex);
        }
    }


    .. setter methods and other stuff ..
}

Some unnecessary details are eliminated (eg. missing setter, etc), assume that code works perfectly fine.

My problem with the above is that when I added the throw random exception line, it does not rollback, the object being persisted through the DAO stays in the db.

I am using Spring 3.1 and Hibernate 3.6 (because there was a bug with Hibernate 4.0 on Spring 3.1)

Thoughts?

Thank you


Solution

  • I found the cause of my problem and why the transaction (seemingly) not managed properly.

    Somewhere in my code

    /**
     * {@inheritDoc}
     */
    @Transactional(rollbackFor=Exception.class, propagation=Propagation.REQUIRED)
    public void doWork(Parameters param) throws ServiceException 
    {
        ... do bunch of stuff ..
        myDao1.persist(entity)
    
        -- Some logic here --
    
        ... do bunch of stuff ..
        myDao2.persist(entity2)
    
        if(true)
            throw new ServiceException("random error")
    }
    

    The part where it says "-- Some logic here --", there was some logic done that uses raw SQL and call on execute update:

    Query query = sessionFactory.getCurrentSession().createSQLQuery(queryText);
    query.executeUpdate();
    

    And because it's not using Hibernate query, and instead using raw SQL execution, it caused a flush to be called and thus any work done prior to the call will be committed along with it.

    I re-work the flow of logic to account for this logic to make sure transaction is managed properly. While using raw SQL might be an indication that there's something wrong - it was something necessary to be done due to the things that the service try to accomplish and to improve the performance of the service.