【问题标题】:How to catch a exception thrown inside of a JTA-Transaction?如何捕获 JTA 事务中引发的异常?
【发布时间】:2026-02-16 00:25:02
【问题描述】:

我正在使用 Spring 3.0.5、Hibernate 3.6.7 和 Atomikos Transactionessentials 3.7.0。在 applicationContext.xml 中使用 AOP 配置的事务。 一切正常。 (提交,回滚)

我的意图是在 jta-transaction 中抛出一个特定的异常。 这样事务应该被回滚,并且我得到了一些关于回滚原因的详细信息。

问题是,我能捕捉到的唯一异常是 atomikos 抛出的回滚事务,告诉我事务意外回滚。

如何在事务之外获得自己的异常?

这里是一个小例子,因为我不知道我的解释是否足够好。 这只是为了演示我的意图。请不要评论任何错别字。

一个特定的异常(也可能是一些标准异常):

public class MySpecialException extends Exception {
    public MySpecialException(String someInfo) {
        super(someInfo);
    }
}

一个接口声明了一个声明抛出异常的方法:

public interface MyInterface {
    Object someJtaTransactionMethod(String param) throws MySpecialException;
}

实现接口的类:

public class MyClass implements MyInterface {
    Object someJtaTransactionMethod(String param) throws MySpecialException {

        // some operations with some errorstate detected
        // so throw the exception:
        throw new MySpecialException("Things went terribly wrong!");

        // some other code
    }
}

还有一些调用函数并捕获异常的代码。

public class Caller {

    @Autowired
    private MyInterface callee;

    public void test() {
        try {
            callee.someJtaTransactionMethod("Some test");
        } catch (MySpecialException mex) {
            // I want to get here
        } catch (Exception ex) {
            // but I only get here
        }
    }
}

这可能吗?

更新:当然,我查看了异常原因。异常本身是 org.springframework.transaction.UnexpectedRollbackException。原因是类 javax.transaction.RollbackTransaction 并且有一个原因 com.atomikos.icatch.RollbackException。

我认为发生的情况是,atomikos 注意到异常并执行回滚(根据需要),但随后 atomikos(可能还有其他 jta 实现)抛出异常,表明事务已回滚(意外)并且我的异常消失了。

更新 2:有趣的是,如果我没有做任何必须回滚的事情,我可以根据需要捕获我的异常!

更新 3 和解决方案:JB Nizet 向我指出了解决方案。事实上,我的事务并没有像我怀疑的那样回滚,但是由于我抛出异常的原因,我遇到了约束违规,因此 atomikos 在提交时抛出了异常。现在,我将事务配置为回滚异常,一切都按预期工作。

【问题讨论】:

  • 我不认识 Atomikos,但会不会是他们抓住了你的异常,并把自己的异常与你的异常一起抛出?您是否分析过异常的 getCause() 方法的返回(从您的第二次捕获)?
  • 是的,我详细查看了异常(在开发过程中不止一次),我尝试对其进行调试,但我找不到任何东西...更新后的帖子
  • 你能提供堆栈跟踪和你正在使用的框架的版本吗?

标签: java spring jpa jta


【解决方案1】:

您的异常是运行时异常还是已检查异常?

如果抛出运行时异常,Spring 默认回滚,如果抛出已检查异常,则默认提交。

从堆栈跟踪来看,您的异常似乎是已检查异常,因此 Spring 尝试提交,但由于 JTA TM (Atomikos) 拒绝提交(例如,因为超时),所以无法提交。

因此,如果您希望此异常导致回滚,请将其设为运行时异常或在 @Transactional 注释的 rollbackFor 属性中声明它。如果它一定不会导致回滚,那么尝试找出 Atomikos 拒绝提交的原因(超时太短,其他的……日志可能会有所帮助)。

【讨论】:

  • 一些有趣的信息。通常,如果我遇到这样的异常,我会调试到 atomikos 并找到真正的原因(例如一些 hibernate 或 jdbc 异常)。明天早上我会继续研究这个问题......我再也睁不开眼睛了。
  • 非常感谢。你拯救了我的一天。我刚刚将我的异常更改为从 RuntimeException 继承,现在一切正常。我之前没有注意到,当我抛出自己的异常时,atomikos 并没有回滚,并且由于抛出异常,我昨天不知何故无法调试到 atomikos。
【解决方案2】:

当您抛出一个继承自 Exception 而不是 MyException 的 MySpecialException 时,这对我来说似乎是一种类型?

否则捕获 MySpecialException 而不是 MyException。

【讨论】:

  • 我已经说过这只是一个例子,错别字不是问题。我的真实代码编译并明确尝试捕获正确的异常(否则编译器会告诉我......)更正它......
最近更新 更多