gpt4 book ai didi

java - UnexpectedRollbackException 覆盖了我自己的异常

转载 作者:搜寻专家 更新时间:2023-10-31 08:24:41 24 4
gpt4 key购买 nike

我在 spring 的事务管理中有以下奇怪的场景:

我有一个调用方法 B 的方法 A,方法 B 调用方法 C,每个方法都在不同的类中。方法 B 和 C 都用事务包装。两者都使用 PROPAGATION_REQUIRED,因此当 spring 创建两个逻辑事务时,数据库中有一个物理事务。

现在,在方法 C 中我抛出一个 RuntimeException。这会将内部逻辑事务设置为 rollbackOnly,并将物理事务也设置为。在方法 B 中,我知道 UnexpectedRollbackException 的可能性,所以我没有继续正常提交。我捕获了来自 C 的异常并抛出另一个 RuntimeException。

我希望外部 RuntimeException 会导致回滚到外部事务,但实际行为是这样的:

  • 外部事务似乎尝试提交,或至少检查其状态,然后它抛出 UnexpectedRollbackException,因为物理事务已被标记为 rollbackOnly。
  • 在抛出该异常之前,它会在日志中打印另一个异常,声明“应用程序异常被提交异常覆盖”。因此,调用方 A 收到的是 UnexpectedRollbackException,而不是 B 抛出的异常。

我找到了解决方法,就是在抛出异常前主动将外层事务设置为回滚

public ModelAndView methodB(HttpServletRequest req, HttpServletResponse resp) {
try{
other.methodC();
} catch (RuntimeException e){
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
throw new RuntimeException ("outer exception");
}
return handleGetRequest(req, resp);
}

但是,此解决方法将代码与事务 API 紧密结合在一起,我想避免这种情况。有什么建议吗?

附注这两个事务都旨在回滚运行时异常。我没有定义任何 rollbackFor 异常或类似的东西

最佳答案

我找到了这个问题的原因。事实证明,methodB 在被包裹在事务中之前被一个基于 cglib 的代理包裹(使用 spring 旧方式,2.0 之前)。所以当我从 methodB 抛出一个 RuntimeException 时,cglib 最终抛出一个 InvocationTargetException,这实际上是一个已检查的异常。

Spring 的事务管理器最终捕获了已检查的异常并尝试提交事务,而没有意识到 methodB 抛出的嵌套运行时异常。发现这一点后,我将事务包装器也设置为回滚已检查的异常,现在它按预期工作。

关于java - UnexpectedRollbackException 覆盖了我自己的异常,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3245788/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com