我一直在发现,我已经存在的事务正在EJB标记为@ejb.transaction type="Required"的任何方法中进行提交。这可以正确吗?

我的期望是,EJB“需要”一个事务意味着:如果已经有一个事务,它将在完成时有礼貌地保持未提交状态,以便无论调用了begin()的人都可以在调用commit()rollback()之前继续使用它进行进一步的操作。 [当然,如果首先没有事务,那么EJB方法将同时调用begin()commit()/rollback()。]

我的期望是错误的,还是应该寻找配置错误?

需要补充一点的是,我正在EJB中使用Hibernate 3。我在调用EJB方法之前获得了UserTransaction。 EJB生成的包装器在退出时调用ServerTransaction.commit(),Hibernate将其 Hook 并利用其机会关闭其Session。我收到的错误是Hibernate延迟加载异常,因为当我尝试访问Hibernate持久对象上的getter时,该 session 已关闭。因此,从技术上讲,我不确定100%是否确定我观察到的ServerTransaction.commit()是否提交了我启动的UserTransaction(也许ServerTransaction.commit()并不总是跟着“真正的”提交?),但是如果不这样做,那该怎么做?是Hibernate关闭Session的依据吗?

更新:我相信我上面的假设是正确的,但是我的观察结果有些偏离。我自己提供的答案,请参见下文。

最佳答案

可能是邪恶的
我个人不喜欢REQUIRED交易属性,因此强烈建议不要使用它。
懒惰地创建事务(这是必需的)导致无法真正知道事务的实际启动时间和位置以及何时提交。那不是好事。人们应该明确设计交易边界。
强制性和UserTransaction是灵魂伴侣
您使用UserTransaction的愿望非常好,并且可以与CMT一起使用-通过容器提供的UserTransaction启动的JTA事务与容器为您启动的JTA事务之间没有区别。
我建议的方法是将所有必需的用法切换为 MANDATORY 。使用MANDATORY,容器将为您而不是启动交易。相反,它将通过确保除非进行事务处理才能调用它来保护您的bean。这是一个了不起的和未充分利用的功能。想要创建一个真正确定性的交易应用并执行它的人,MANDATORY是最好的 friend 。通过此设置,您可能会爱上CMT。
在这种情况下,可以用UserTransactions启动事务,然后容器就像您的保镖将人们踢到路边,除非他们在尝试调用您的代码之前已经适本地启动了事务。
注意事项

  • Servlet或BMT EJB可以使用UserTransaction。
  • CMT Bean无法使用UserTransaction,但是它们可以参与由UserTransaction启动的事务(如上所述,JTA事务是JTA事务)。
  • BMT Bean无法参与现有事务。如果在事务正在进行时调用BMT Bean,则容器将在调用BMT Bean之前暂停事务,并在方法完成后恢复事务。
  • @Resource UserTransaction将通过注入(inject)
  • 为您提供用户交易
  • java:comp/UserTransaction将通过查找
  • 为您提供用户交易
    在类级别使用的
  • @TransactionAttribute(MANDATORY)将影响该确切类的方法(即fooClass.getDecaredMethods()方法)。 super 类和子类的方法将默认为@TransactionAttribute(REQUIRED),除非这些类也已显式标记为@TransactionAttribute(MANDATORY)
  • 如果您厌倦了调用userTransaction.begin()userTransaction.commit()并进行相关的异常处理,请考虑使用@TransactionAttribute(REQUIRES_NEW)。您的交易边界仍将被记录在案并且是明确的。
  • 即使您在调用代码中捕获并处理了异常,从CMT bean的方法抛出的
  • RuntimeException也会导致将事务标记为回滚。对于定制的运行时异常类,请根据具体情况使用@ApplicationException禁用此功能。

  • 失去交易环境
    有几件事可能导致正在进行的事务停止,挂起或传播到被调用的bean。
  • BMT Bean停止事务传播。如果正在进行的事务调用BMT Bean,则该事务将在BMT Bean被调用之前被挂起,并在Bean返回之后恢复。 BMT bean可以是事务的来源,但不能参与现有事务。如果传播神秘地失败了,请确保在交易中间不会无意中调用BMT bean。
  • 除了使用容器提供的UserTransaction或容器提供的方法(如SessionContext.setRollbackOnly)之外,请勿使用其他任何东西来管理事务。使用“资源管理器特定的事务划分API”(例如JPA EntityTransactionjava.sql.Connection.commit() )将规避事务管理。
  • 不要启动自己的线程。事务传播基于每个线程发生。 Java EE中有 no 标准API,它们支持跨多个线程的事务。如果通过启动自己的线程或使用@Asynchronous离开线程,则将现有事务保留下来。
  • 10-06 14:59