hibernate Spring @Transaction不会在抛出异常时回滚

rsaldnfx  于 2023-01-09  发布在  Spring
关注(0)|答案(5)|浏览(130)

我已经搜索了这个问题,有相当多的他们在这里的StackOverflow和谷歌,但我似乎不能得到任何为我工作。
下面是我的代码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 ..
}

和一个刀类:

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 random异常行时,它不会回滚,通过DAO持久化的对象仍保留在数据库中。
我使用的是Spring 3.1和Hibernate 3.6(因为Spring 3.1上的Hibernate 4.0有一个bug)
有什么想法?
谢谢

mnemlml8

mnemlml81#

我找到了问题的原因,以及为什么事务(看起来)没有得到正确管理。
在我的代码里

/**
 * {@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并调用execute update的逻辑:

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

因为它没有使用Hibernate查询,而是使用原始SQL执行,所以它导致了一个刷新被调用,因此在调用之前所做的任何工作都将与它沿着提交。
我重新设计了逻辑流来解释这个逻辑,以确保事务得到正确的管理。虽然使用原始SQL可能表明存在问题-但由于服务试图完成的事情以及提高服务性能,这是必须要做的事情。

vsikbqxv

vsikbqxv2#

这是事务管理的预期行为。@Transactional的默认行为是仅对运行时异常进行回滚。如果您希望在抛出DaoException后回滚,请将其添加到回滚异常列表中。不要忘记还包括RuntimeException。在Dao类@Transactional上尝试以下操作(propagation=Propagation.Mandatory,rollbackFor={RuntimeException.class,DaoException.class})

tsm1rwdh

tsm1rwdh3#

尝试从DaoImpl类中删除@Transactional注解。我怀疑可能发生的情况是,当事务跨越事务边界(DaoImpl)时,事务正在被提交。我在此设置中获得了好坏参半的成功。您可以尝试一些不同的事务方法来处理“内部”事务。
你可以做的另一件事是打开spring事务日志。它认为它的类别是org.springframework.transaction或其他什么。这样你就会看到它在做什么w.r.t来回滚和提交事务...

bvjxkvbb

bvjxkvbb4#

您没有缺省情况下处于AUTOCOMMIT模式的JDBC驱动程序,是吗?

t3irkdon

t3irkdon5#

我在Spring仓库中手动打开连接时遇到了同样的问题。开始使用JdbcTemplate后,错误消失了
我以前

@Autowired 
private JdbcTemplate jdbc;

在我的存储库中
然后是jdbc.query(sql, new RowMapper());jdbc.update(sql);jdbc.queryForObject(sql, new RowMapper());,具体取决于查询返回的对象数量。
我还定义了RowMapper():

public class RowMapper implements RowMapper<YourDTOObject> {
    @Override
    public YourDTOObject mapRow(ResultSet resultSet, int i) throws SQLException {
        YourDTOObject dto = new YourDTOObject();
        dto.setId(resultSet.getInt("id")); // here you can change to your column names
        dto.setName(resultSet.getString("name"));
        dto.setAmount(resultSet.getBigDecimal("amount"));
        return a;
    }

相关问题