【问题标题】:Spring @Transactional method Error handlingSpring @Transactional 方法错误处理
【发布时间】:2019-02-26 21:10:31
【问题描述】:

我正在使用使用@Transactional 注释的事务方法。我正在尝试使用 JpaRepository 的 save() 方法将对象保存到数据库中。 (由于数据库关系的限制,这将引发错误。)

现在,当我调试程序时,我发现在事务方法结束时抛出异常,而不是在调用save 方法时。这与非事务方法的行为完全不同。

有人可以解释为什么会这样吗?为什么在事务方法结束时抛出异常,而不是实际应该发生的时候。

我的第二个问题是,当方法是事务性时,抛出的异常是DataViolationException,当它是非事务性时,抛出的异常是PSQLException(使用 Postgres 数据库)。为什么呢?

下面是代码

@Transactional
public ResponseType methodA(UserObject userObject) {
    //save call
    jpaRepoObject.save(userObject);
    //next call will fail due to relational constraints on database
    jpaRepoObject.save(userObject); //should throw PSQLException/DataViolationException

     return new ResponseType("success"); //Error thrown after this line.
}

【问题讨论】:

  • 因为只在事务结束时才进行保存
  • 能否请您发布您的代码,以便我们修复它?
  • 更相关的是,告诉我们什么异常和消息(在这种情况下不一定是堆栈跟踪)。
  • @NielsNet 如果交易包含多个保存调用怎么办。它们都将在交易结束时完成吗?如果下一次保存依赖于上一次保存和其他代码怎么办?
  • @JBDouble05 用代码更新了帖子!

标签: java spring exception-handling spring-data-jpa transactional


【解决方案1】:

这是 JPA 的一个特性,称为事务性后写。您的代码正在执行的所有插入和更新都由 Jpa 实现存储,直到事务被刷新。这让 jpa 实现重新排序这些操作,以最有意义的顺序发生。

刷新意味着执行 entityManager 实例迄今为止存储的所有操作。您可以告诉 entityManager 刷新,或者一旦达到事务边界,它将自动刷新。

如果您要插入一个实体并且需要为它生成一个 ID,以便以后可以在同一方法中使用它,那么您将显式刷新的一个示例。

您始终可以在事务中运行 sql 并稍后提交或回滚。 Flushing 运行 sql 但不提交。

【讨论】:

  • 感谢您提供信息,内森。只是想澄清这一点!因此,在事务方法的情况下,无论我使用 save() 还是 saveAndFlush(),都将在事务方法结束时完成提交或回滚。对吗?
  • 另外,你能不能也回答我的第二个问题。在事务性和非事务性方法的情况下,我在同一操作中得到 2 个不同的异常。会有很大帮助的!谢谢!
  • Rishabh:事务将提交或回滚,无论如何。当您删除 @Transactional 注释时,每个语句都会在其自己的事务中执行。
【解决方案2】:

save 不会立即将数据刷新到底层数据库。首先,实体被保存到一级缓存中,并且,当刷新时间到来时(在事务结束时 - 例如在您的情况下,或发出查询时),只有实体被保存到数据库中。

要查看您期望的行为,请使用saveAndFlush 方法。

【讨论】:

  • 但是当我从我的方法中删除 @Transactional 注释时,错误会从保存调用本身引发!你能解释一下这种行为吗?
  • 另外,如果我使用 saveAndFlush(),整个事务方法是否仍然能够在出错时回滚?
猜你喜欢
  • 1970-01-01
  • 2023-03-07
  • 2019-03-30
  • 2018-10-13
  • 2022-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多