【问题标题】:In a JavaEE stateless session bean, why is the SessionContext responsible for rolling transactions back and not the EntityManager?在 JavaEE 无状态会话 bean 中,为什么 SessionContext 负责回滚事务而不是 EntityManager?
【发布时间】:2023-03-05 21:04:01
【问题描述】:

对我(JavaEE 开发新手)来说,我认为容器管理的 EntityManager 将负责回滚失败的事务,而不是 SessionContext 实例。假设以下场景...

@Stateless
public class MySessionBean implements MySessionBeanRemoteInterface {
    @PersistenceContext(unitName="MYPu")
    private EntityManager em;

    @Resource
    private SessionContext sctx;

    @Override
    public StackOverFlowUser createSOUser(String userName, int rep) {
         try {
             StackOverFlowUser su = new StackOverFlowUser();
             su.setUserName(stackOverflowName);
             su.setRep(rep);
             su.setIsBalusC(userName.equals("BalusC");
             su.setIsTheJonSkeet(userName.equals("jon skeet"));
             return em.merge(su);
         } catch (Exception e) {
             //sctx.setRollbackOnly();
             return null;
         }
    }

}

为什么 EntityManager 不对此负责?为什么要使用 SessionContext?

【问题讨论】:

    标签: jakarta-ee jboss hibernate-entitymanager


    【解决方案1】:

    因为您告诉容器通过 JTA (transaction-type="JTA") 而不是 JPA (transaction-type="RESOURCE_LOCAL") 管理事务。 JTA 反过来由 EJB 容器管理。因此SessionContext 的作用就在这里。

    但令我困扰的是,您正在抑制异常并返回 null。您最好不要在业务服务方法中这样做。你最好让异常消失而不是返回null。 EJB 容器将在任何异常情况下自动执行回滚。去掉 EJB 中的 try-catchreturn null,让 EJB 的客户端自己处理异常。

    例如

    try {
        mySessionBean.createSOUser(userName, rep);
    } catch (PersistenceException e) {
        showSomeGlobalErrorMessage(e.getMessage());
    }
    

    或者,更好的是,让它进一步进入底层容器。例如。如果它实际上是一个 servlet 容器:

    <error-page>
        <exception-type>javax.persistence.PersistenceException</exception-type>
        <location>/WEB-INF/errorpages/db-fail.xhtml</location>
    </error-page>
    

    或者,也许有问题的 MVC 框架甚至有一个可定制的全局异常处理程序。至少,JSF 允许这个机会,然后您可以全局设置一个 faces 消息,而无需在调用服务方法的托管 bean 方法中的所有位置重复 try-catch

    另见:

    【讨论】:

    • 伙计,这就像得到名人的亲笔签名!我发现你的回答很有帮助。但是,我想知道如果 EntityManager 负责持久化、合并、删除等,它不负责回滚的原因是什么。对我来说(也许我在这里遗漏了一个概念或者没有真正理解预期的功能EntityManager)看起来回滚将是EntityManager的功能之一。是因为需要 Session 中的数据(由于容器管理的事务)来回滚事务吗?
    • 是的,但是在委托给 JTA 时,EJB 会接管它,因此您无需担心回滚。这样你的代码就更多了DRY。或者你真的打算在每一个服务方法中都放一个 try-catch-rollback 吗?这打败了 EJB+JTA 的工作。另请参阅第二个“另请参阅”链接(可能还有其中的“另请参阅”链接)。
    • 我不打算这样做。但是,我上面作为示例的代码结构是在我正在处理的现有应用程序中。我个人会按照你说的做,而不是返回 null,我会在方法上添加一个 throws 并抛出异常。感谢您的指导(以及过去几个月我一直在阅读的所有教程)。
    • 不客气 :) 您不一定需要添加 throws 也不必自己抛出异常。当查询返回异常结果时,JPA 将执行此操作。除非 JPA 在根据您的业务需求异常的情况下不抛出异常。然后,您当然可以随意抛出自定义异常,只要它带有 @ApplicationException(rollback=true) 注释即可。然后 EJB 也将透明地执行回滚。
    猜你喜欢
    • 2014-04-06
    • 2014-06-23
    • 1970-01-01
    • 1970-01-01
    • 2011-10-30
    • 2010-09-13
    • 2016-04-14
    • 2017-09-15
    • 1970-01-01
    相关资源
    最近更新 更多