EJB3 事务回滚

38

我在 EJB3 无状态会话 Bean 中使用 CMT。同时,我创建了一个带有 "@ApplicationException (rollback=true)" 注解的自定义异常。

  1. 当我想回滚事务时,我是否需要使用 "context.setRollbackOnly()"?

  2. 答:是的,您需要使用 "context.setRollbackOnly()" 来回滚事务。
  3. 我是否可以通过在bean中的公共方法中抛出异常来回滚事务?

  4. 答:是的,您可以通过在bean中的公共方法中抛出异常来回滚事务。
  5. 如果是这样(问题2的答案为是),我是否需要在方法中声明异常将异常抛出方法外部,或者只在方法内部抛出异常并在同一方法内处理它就足够了?(我不想将异常传播到下一个级别。我只想回滚异常。)

  6. 答:是的,如果您只想回滚异常并且不想将其传播到下一个级别,那么在方法内部抛出异常并在同一方法内处理它就足够了。

提前感谢。;)

2个回答

80

首先,不存在异常的回滚,只有事务的回滚。

  1. 如果你使用 @ApplicationException(rollback=true) 抛出异常,你就不需要手动回滚事务。调用 Context.setRollbackOnly() 强制容器回滚事务,即使没有异常抛出。
  2. 一个被检查的异常本身不会回滚事务。必须使用注解 @ApplicationException(rollback=true)。如果该异常是 RuntimeException 类型且未被捕获,它会强制容器回滚事务。但要注意,容器将在这种情况下丢弃 EJB 实例。
  3. 如第二点所述,如果你抛出 RuntimeException,事务将自动回滚。如果你在代码中捕获了被检查的异常,你必须使用 setRollbackOnly 回滚事务。

更多信息请参阅免费书籍《Mastering EJB》。它很好地描述了回滚场景,并可供下载


如果在代码中捕获了一个已检查异常,您必须使用setRollbackOnly来回滚事务。您也可以抛出相同的异常并回滚事务吗? - ruwan.jayaweera
你可以使用throws子句抛出相同的异常,但是事务不会回滚。如果你想在这种情况下回滚事务,你必须在你的异常中添加@ApplicationException(rollback=true)。另一种方法是将已检查的异常包装在未检查的异常中(例如RuntimeException)。但这种方式并不是真正推荐的,因为如果抛出RuntimeException,容器会丢弃bean实例并创建一个新的实例。 - Steve
2
我之前因为类似的原因查看了这个答案,想指出你提供的书籍在该网站上已不再提供完整版本,而且它是2006年的,非常过时,在JEE5和JEE6环境下可能没有太大用处。 - Bill Rosmus
1
EJB 3.1的最终规范指出,应用程序异常是任何带有@ApplicationException注释的CheckedException或RuntimeException。 - Andrés Oviedo
4
在我看来,这似乎是极其不良的行为,如果有例外情况,我认为显然应该回滚!有人知道为什么会出现这种情况吗? - Emmanuel Touzery
3
检查异常是方法签名的一部分,因此被认为是“预期”的和非错误行为。现在,有些人使用检查异常作为方法的常规响应,而不是返回一个值。例如,它可以携带有关业务案例结果的信息。这就是为什么检查异常默认情况下不会回滚事务(因为它们是签名的一部分),但运行时异常会回滚事务(因为它们不是签名的一部分)。 - fxnn

0

如何防止在注释中声明的检查异常在抛出时导致回滚被传播到“上层”的问题尚未在此处得到解答。

我认为这将需要一个包装器来包装相关的EJB,以吞噬抛出的异常。(换句话说:我认为自定义异常必须在方法边界处抛出(因此不能在方法内部捕获和处理),并传播以产生事务效果--也将导致EJB实例的销毁。)


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接