【问题标题】:Spring Hibernate rollback failure during auto flush/commit leaving transactional method自动刷新/提交离开事务方法期间的 Spring Hibernate 回滚失败
【发布时间】:2017-04-12 20:35:03
【问题描述】:

嗯,这是我的第一篇文章,所以我真的必须摸不着头脑,因为这里的资源非常好。

Spring MVC 4.2.5。 hibernate-core-5.1.0 JDK8

我遇到了一个问题,即在离开调用的 @Transactional 方法时事务没有回滚。我正在调用的方法具有适当的设置:

@Transactional(propagation=Propagation.REQUIRED,readOnly=false,rollbackFor = Exception.class)
public byte process(CommonDataBlock commonDataBlock) throws Exception   {

该方法调用 dao 对象,假设我们保存了大约 8 个对象(“到数据库”),例如:

applicationPartyDao.saveApplicationParty(appParty);

使用典型的 dao 只需执行以下操作:

this.getSessionFactory().getCurrentSession().save(appParty);

一开始,我从普通 POJO 调用上述事务方法“进程”:

        try {
        // Database transaction starts/ends here
        submitAccess.process(commonDataBlock);
    }
        catch (Exception e) {
            logUtil.debug(this, "Error submitting application: "+e.getMessage());
            e.printStackTrace();
            return Codes.RET_BYPASS_ALL_ADAPTORS;
    }

(那个注释不太对,数据库事务在'process'方法开始和结束。)

所以 - 当“进程”中的代码出现错误时,它都会“回滚”(有意引用)。但是当出现 FK 问题或 NOT NULL 列保留为空等数据库错误时,它不会回滚。

上面的引号是故意的,因为我意识到它实际上并没有像我想的那样从“进程”方法中的错误成功回滚,因为它还没有写入数据库。退出时执行此操作。

数据库错误发生在流程方法和调用pojo之间。 Hibernate 已存储第一级数据并开始将所有对象写入数据库。

我已经尝试在“进程”方法中对所有内容进行 try/catch,但由于那里没有发生错误(当它离开方法时动作开始!)所以没有任何东西被抛出和捕获。

调用 pojo 确实捕获了一个错误(并且可以看到 not null 的数据异常错误),但它已将对象写入数据库并在错误发生之前将它们留在那里。

rollbackFor 很好,但故障似乎在那之后 - 它在该方法中捕获错误,但是当它离开该方法并且 Spring/Hibernate 完成它的事情并提交时......它留在了数据库中。没有回滚。所以 rollbackFor 似乎只适用于关联方法中的错误,而不是之后自动发生的事情(后面写)

几乎像自动提交行为,但不应该是 Hibernate (Oracle 10) 的情况。

有什么想法吗?我将在今天放入一个 flush() 以查看这是否会使错误发生在 process 方法中并因此被 rollbackFor 捕获...但我们不应该这样做吗? (如果可行的话)

谢谢

【问题讨论】:

    标签: spring hibernate transactions


    【解决方案1】:

    知道了。问题是我要更改事务管理器的名称:

    <bean id="transactionManager_guardianship"  class="org.springframework.orm.hibernate5.HibernateTransactionManager"> 
        <property name="sessionFactory" ref="sessionFactory_guardianship" />
        <property name="dataSource"><ref bean="dataSource_guardianship"/></property>
    </bean>
    

    如果您没有将它作为“transactionManager”,我会在某处读到它,它不会找到它。有道理(我也按名称查找上下文内容!很明显!)。我这样做是因为我有两个不同的数据库用于不同的数据库。

    所以我添加了一个限定符:

    <bean id="transactionManager_guardianship"  class="org.springframework.orm.hibernate5.HibernateTransactionManager"> 
        <property name="sessionFactory" ref="sessionFactory_guardianship" />
        <property name="dataSource"><ref bean="dataSource_guardianship"/></property>
        <qualifier value="txGuardianship"/>
    </bean>
    

    ...并在服务类中引用了正确的事务:

    @Transactional(value="txGuardianship", propagation=Propagation.REQUIRED,readOnly=false,rollbackFor = Exception.class)
    public byte process(CommonDataBlock commonDataBlock) throws Exception   {
    

    这是在事务管理器名称更改时,加上(更改的原因)当我有两个时。另一个类似的@Transactional(value= 设置。

    干杯

    【讨论】:

      猜你喜欢
      • 2013-06-07
      • 2015-11-09
      • 1970-01-01
      • 2018-09-21
      • 1970-01-01
      • 1970-01-01
      • 2020-01-19
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多