Question

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

Was it helpful?

Solution 2

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.

OTHER TIPS

That is the intended behavior of transaction management. The default behavior for @Transactional is to rollback only for runtime exceptions. If you want your stuff to rollback after throwing DaoException then add it to the rollback exception list. Don't forget to also include RuntimeException also. Try the following on the Dao class @Transactional(propagation=Propagation.Mandatory, rollbackFor={RuntimeException.class, DaoException.class})

Try remove the @Transactional annotation from the DaoImpl class. I suspect what might be happening is that the transaction is being committed when it crosses back over that transaction boundary (DaoImpl). I've had mixed success with this setup. You can try some different transaction approaches to the "inner" transaction.

The other thing you can do is turn on spring transaction logging. It think its category org.springframework.transaction or something. That way you will see exactly what it is doing w.r.t to roll back and commit of transactions...

you don't have one of those JDBC drivers that are in AUTOCOMMIT mode by default, do you?

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top