Spring @Transaction在抛出Exception时不回滚

时间:2012-02-17 21:23:45

标签: java hibernate spring-3

我一直在寻找这个问题,StackOverflow和Google上有很多这样的问题,但我似乎无法为我工作。

这是我的代码 Spring配置:(我不使用任何切入点 - 我想我不需要?)

<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"/>

我有一个服务类:

@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 ..
}

和Dao班:

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

消除了一些不必要的细节(例如,缺少setter等),假设代码完全正常。

我上面的问题是,当我添加throw随机异常行时,它不会回滚,通过DAO持久化的对象会保留在db中。

我正在使用Spring 3.1和Hibernate 3.6(因为在Spring 3.1上存在Hibernate 4.0的错误)

思想?

谢谢

4 个答案:

答案 0 :(得分:11)

这是事务管理的预期行为。 @Transactional的默认行为是仅针对运行时异常进行回滚。 如果你希望你的东西在抛出DaoException之后回滚,那么将它添加到回滚例外列表中。不要忘记还包括RuntimeException。 在Dao课上尝试以下内容 @Transactional(propagation = Propagation.Mandatory,rollbackFor = {RuntimeException.class,DaoException.class})

答案 1 :(得分:11)

我找到了问题的原因以及为什么交易(貌似)管理得不好。

我的代码中的某处

/**
 * {@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")
}

它所说的部分“ - 这里有一些逻辑 - ”,有一些使用原始SQL并调用执行更新的逻辑:

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

因为它没有使用Hibernate查询,而是使用原始SQL执行,它导致调用flush,因此在调用之前完成的任何工作都将与 它。

我重新处理逻辑流程以解释此逻辑,以确保正确管理事务。虽然使用原始SQL可能表明出现了问题 - 由于服务试图完成的事情以及提高服务性能,这是必须要做的事情。

答案 2 :(得分:1)

尝试从DaoImpl类中删除@Transactional注释。我怀疑可能发生的事情是当事务跨越该事务边界(DaoImpl)时正在提交事务。我在这个设置上取得了不错的成功。您可以尝试一些不同的交易方法来进行“内部”交易。

您可以做的另一件事是打开spring transaction logging。它认为它的类别org.springframework.transaction或其他东西。这样你就可以看到w.r.t正在做什么来回滚和提交交易...

答案 3 :(得分:0)

默认情况下,您没有其中一个处于AUTOCOMMIT模式的JDBC驱动程序,是吗?