【问题标题】:EJB Transactions in local method-calls本地方法调用中的 EJB 事务
【发布时间】:2010-09-30 11:00:13
【问题描述】:

在以下设置中,方法 B 是否在(新)事务中运行?

一个 EJB,有两个方法,方法 A 和方法 B

public class MyEJB implements SessionBean
    public void methodA() {
       doImportantStuff();
       methodB();
       doMoreImportantStuff();
    }

    public void methodB() {
       doDatabaseThing();
    }
}

EJB 是容器管理的,methodB 在 requires_new 事务中,method A 在 required 事务中。因此:

<container-transaction id="MethodTransaction_1178709616940">
  <method id="MethodElement_1178709616955">
    <ejb-name>MyName</ejb-name>
    <method-name>*</method-name>
  <trans-attribute>Required</trans-attribute>
  </method>
  <method id="MethodElement_1178709616971">
    <ejb-name>MyName</ejb-name>
    <method-name>methodB</method-name>
  </method>
  <trans-attribute>RequiresNew</trans-attribute>
</container-transaction>

现在让另一个 EJB 通过 EJB 方法调用来调用 methodA。 methodA 现在在事务中运行。从 methodA 对 methodB 的后续调用会在同一个事务中运行,还是在新事务中运行? (注意,这里是实际的代码。没有显式的对方法 B 的 ejb 调用)

【问题讨论】:

    标签: jakarta-ee transactions ejb


    【解决方案1】:

    你对methodB()的调用是一个普通的方法调用,不会被EJB容器拦截;在运行时,EJB 容器将注入 proxy 而不是您的类的实例,这是它在调用您的方法之前拦截调用并设置环境的方式。如果您使用this,您将直接调用一个方法,而不是通过代理。因此,这两种方法都将使用相同的事务,而不管 ejb-jar.xml 中为通过 EJB 接口的调用定义了什么。

    【讨论】:

    • 除了大卫发布的内容,你应该阅读java.sun.com/j2ee/tutorial/1_3-fcs/doc/Transaction3.html
    • 问题:这在 EJB 3.1 和注释中仍然成立吗?我认为是这样,因为本地方法调用和 EJB 调用之间的区别仍然存在。
    • @wrschneider99 是的,完全正确。我认为值得一提的是,修复方法是注入对与 user1656654 所说的相同对象(对于无状态或单例)的引用,或者使用 SessionContext.getEJBLocalObject、getEJBObject 或 getBusinessObject(可能使用 getInvokedBusinessInterface)来获取到当前对象。
    • 我有一个子问题。在我有一个 bean 的情况下: ThingFacade 并且我将同一个 bean 注入其中.... @EJB ThingFacade thingFacade;通过从 thingFacade 中的另一种方法通过 thingFacade 引用调用一个 ThingFacade 方法,我是否要通过代理...或不?
    【解决方案2】:

    注入 SessionContext,并要求它提供您的代理实例:

    @Stateless
    public class UserFacade implements UserFacadeLocal {
        @Resource
        private SessionContext context;
    
        @Override
        @TransactionAttribute(TransactionAttributeType.REQUIRED)
        private void create(User user) {
            System.out.println("Users Count: "+count()); //invocation#1
            System.out.println("Users Count Through Context: "+context.getBusinessObject(UserFacadeLocal.class).count()); //invocation#2
        }
    
        @Override
        @TransactionAttribute(TransactionAttributeType.NEVER)
        public int count() {
            return ((Long) q.getSingleResult()).intValue();
        }
    }
    

    在'invocation#1'中这是一个本地调用,不通过代理,它会返回计数

    在“invocation#2”中,这是通过代理的调用,因此您将其注释为不支持事务(现在由 create(user) 方法打开),此调用将引发事务异常:

    javax.ejb.EJBException:无法在全局事务中调用 EJB

    【讨论】:

    • 有趣的 hack,我想知道这样做是否有任何总体缺点,除了与 EJB 和 Spring 通过事务代理工作的普遍共识不一致,因此在本地方法调用中忽略事务注释等,这显然会影响设计
    • @nvrs,这只是我用来了解代理如何工作的代码,但我不知道如何在现实生活中使用它。
    【解决方案3】:

    他们将使用相同的交易。

    如果我没记错的话,事务是由容器“在”调用方法“之前”开始的,并在“完成”之后提交。

    由于“a”调用“b”,“b”将使用相同的事务。

    :S

    我想你能做的最好的事情就是测试它来验证它! :)

    【讨论】:

      猜你喜欢
      • 2015-03-01
      • 1970-01-01
      • 2017-06-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-01-13
      • 1970-01-01
      相关资源
      最近更新 更多