Jakarta ee 当事务属性为“时,为什么CMT在EJB方法退出时提交;“必需”吗;?

Jakarta ee 当事务属性为“时,为什么CMT在EJB方法退出时提交;“必需”吗;?,jakarta-ee,transactions,ejb,java-ee-6,ejb-3.1,Jakarta Ee,Transactions,Ejb,Java Ee 6,Ejb 3.1,我始终发现,我已经存在的事务正在标记为@EJB.transaction的EJB的任何方法中提交。transactiontype=“Required”。这是正确的吗 我的期望是,一个EJB“需要”一个事务意味着:如果已经有一个事务,那么在完成时它会礼貌地让它保持未提交状态,这样无论谁调用begin()都可以在调用commit()或rollback()之前继续使用它进行进一步的操作。[当然,如果一开始没有事务,那么EJB方法将调用begin()和commit()/rollback()] 我的期望是错

我始终发现,我已经存在的事务正在标记为
@EJB.transaction的EJB的任何方法中提交。transaction
type=“Required”
。这是正确的吗

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

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

可能需要补充一点,我在EJB中使用Hibernate 3。在调用EJB方法之前,我正在获取一个UserTransaction。EJB生成的包装器在退出时调用
ServerTransaction.commit()
,Hibernate钩住并利用机会关闭其会话。我得到的错误是Hibernate延迟加载异常,因为当我尝试访问Hibernate持久化对象上的getter时,会话已关闭。因此,从技术上讲,我不能100%确定我观察到的
ServerTransaction.commit()
是否一定提交了我启动的
UserTransaction
(可能
ServerTransaction.commit()
并不总是实际执行“真正的”提交?),但如果没有,那么Hibernate关闭会话的依据是什么


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

这就是CMT管理事务的工作方式。当业务方法返回时,容器自动提交事务。如果你不想用这种行为来代替CMT。

仔细观察会发现一个不同于上述建议的答案。我实际看到的是,我启动的UserTransaction仍然保持打开状态,但是CMT在EJB方法的条目上创建了一个新的事务,尽管有“Required”属性

我相信这是因为我违反了规则在使用CMT时,您不应该访问UserTransaction API。CMT很高兴地忽略了我的UserTransaction,开始了自己的UserTransaction,取代了它作为所有事务边界仲裁者的位置。因为它启动了事务,所以它也提交了事务,当然我的UserTransaction没有被触动

在我看来,这似乎是脆弱和愚蠢的,也许是一种天真的观点,但在我阅读时,它似乎符合“规则”。我不知道为什么CMT选择不处理从更高级别开始的用户事务。也许是为了迫使开发人员“做正确的J2EE事情”,并创建另一个会话bean层来处理更广泛的事务上下文。这将起作用,因为CMT将管理外部事务,因此可以登记任何内部事务,我相信在这种情况下,“伞式”事务不会由内部EJB提交;CMT将等待外部事务完成,然后提交整个事务。事实上,这是必须的

我不想在这个已经膨胀的EJB应用程序中创建更多的会话EJB,但它可能是唯一的解决方案,除了在我不想接触的一大堆地方撕毁CMT之外。

所需的可能是邪恶的 我个人不喜欢必需的事务属性,强烈反对使用它

懒散地创建事务(这是必需的)会导致不知道事务何时何地实际启动以及何时提交。这不是一件好事。人们应该明确地设计事务边界

强制和用户事务是灵魂伴侣 您使用
UserTransaction
的愿望非常好,并且与CMT一起工作——通过容器提供的UserTransaction启动的JTA事务与容器为您启动的JTA事务之间没有区别

我建议的方法是将所有必需的用法切换到强制。在强制模式下,容器不会为您启动事务。相反,它将通过确保除非事务正在进行中,否则不能调用bean来保护您的bean。这是一个令人惊讶且未充分利用的功能。对于那些想要创建一个真正确定的事务应用程序并实施它的人来说,强制性是最好的朋友。使用此设置,您可能会爱上CMT

在这种情况下,使用
UserTransactions
启动事务,然后容器就像您的大保镖将人踢到路边,除非他们在尝试调用您的代码之前正确启动了事务

考虑
  • Servlet或BMT EJB可以使用UserTransaction

  • CMT bean不能使用UserTransaction,但它们可以参与由UserTransaction启动的事务(如上所述,JTA事务就是JTA事务)
  • BMT bean不能参与现有事务。如果在事务正在进行时调用BMTBean,那么在调用BMTBean之前,容器将暂停该事务,并在方法完成后恢复该事务
  • @Resource UserTransaction
    将通过注入获得用户事务
  • java:comp/UserTransaction
    将通过查找获得用户事务
  • 类级别使用的
    @TransactionAttribute(必填)
    将影响该确切类的方法(即
    fooClass.getDecardMethods()
    方法)。超类和子类的方法将默认为
    @TransactionAttribute(必需)
    ,除非这些类也被显式注释为
    @Transac