【问题标题】:Spring nested transaction marked as rollbackonly with unchecked exceptionSpring嵌套事务​​标记为rollbackonly,带有未经检查的异常
【发布时间】:2012-07-15 21:08:21
【问题描述】:

我对 Spring 和事务还很陌生。我确信这个问题之前已经被问过,但我仍然无法找到正确的解决方法。

我正在使用 Spring 和休眠。我有一个这样的服务方法:

@Transactional
public void processPendingReport(Report report) {
  try {
    // Do processing stuff, update report object state
    reportDAO.save(report);
  } catch (Exception e) {
    reportDAO.markReportAsFailed(report);
  }
}

如果在处理过程中发生 RuntimeException,则会抛出“事务标记为 rollbackOnly”RollbackException,因此报告不会被标记为失败(尽管我希望这样)。

我尝试过使用@Transactional(noRollbackFor=Exception.class),但仍然遇到同样的问题。有什么建议吗?会不会是配置问题?

【问题讨论】:

  • reportDAO 类是否也标记为@Transactional?
  • 什么是用于reportDAO.save 和reportDAO.markReportAsFailed 的事务传播?
  • reportDAO 在类级别被标记为@Transactional。 applicationContext.xml中没有explixit tx:advice声明,所以应该是默认的,REQUIRED传播级别
  • 你提到的这个rollbackException,是javax.persistence.RollbackException吗?如果是这样,它应该只出现在事务结束时,即提交时。您可以在保存方法之前检查事务状态以检查它是否尚未标记为回滚吗?还是“markReportAsFailed”方法是抛出rollbackException的方法?
  • 我认为您应该尝试使用 REQUIRES_NEW 的 reportDAO.markReportAsFailed 事务,因为您希望父事务作为回滚但markReportAsFailed 被提交

标签: spring hibernate transactions


【解决方案1】:

如果在reportDAO.save()reportDAO.markReportAsFailed() 中发生数据库异常(例如违反约束),则无论您在应用程序级别执行什么操作,事务都将在数据库级别回滚。

当您为reportDAO.markReportAsFailed() 创建新事务时,如果reportDao.save() 失败,您仍然可以将报告标记为失败。由于ReportDAO 被注释@Transactional 只需从服务方法中删除@Transactional 注释。您还可以更改 reportDAO.save() 实现以使用数据库函数或存储过程来包装插入语句并捕获数据库级别的任何异常。

HTH。

【讨论】:

  • 错误不是出现在db级别,而是出现在代码中。因此,在“//do processing stuff”部分,我有时会收到 NullPointerException,整个(外部)事务被回滚,这不允许 markReportAsFailed 执行并实际更改报告状态。
猜你喜欢
  • 2015-11-09
  • 2014-10-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-02-22
  • 2014-06-04
相关资源
最近更新 更多