EJB Transactions in local method-calls
Asked Answered
F

3

23

In the following setup, does method B run in a (new) transaction?

An EJB, having two methods, method A and method B

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

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

The EJB is container managed, with methodB in requires_new transaction, and method A in required transaction. thus:

<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>

Now let another EJB call methodA with an EJB method call. methodA now runs in an transaction. Will the subsequent call to methodB from methodA run in the same transaction, or does it run in a new transaction? (mind, it's the actual code here. There is no explicit ejb-call to method B)

Flapdoodle answered 9/1, 2009 at 9:2 Comment(0)
K
40

Your call to methodB() is an ordinary call of a method, not intercepted by the EJB container; at run-time the EJB container will inject a proxy and not an instance of your class, this is the way it intercepts calls and setup the environment before calling your method. If you use this you're calling a method directly and not through the proxy. Hence both methods will use the same transaction, regardless to what is defined in ejb-jar.xml for calls through EJB interfaces.

Kata answered 9/1, 2009 at 10:9 Comment(6)
In addition to what david posted, you should read java.sun.com/j2ee/tutorial/1_3-fcs/doc/Transaction3.htmlIronworks
Question: is this still true in EJB 3.1 and with annotations? I think so, because the distinction would still remain between local method calls and EJB invocations.Riyadh
@wrschneider99 Yes, exactly. I think it's worth mentioning that the fix is to either inject a reference to the same object (for stateless or singleton) as user1656654 said, or to use SessionContext.getEJBLocalObject, getEJBObject, or getBusinessObject (possibly with getInvokedBusinessInterface) to get a proxy to the current object.Site
@user674669 here it goes: web.archive.org/web/20120627044942/http://java.sun.com/j2ee/…Ironworks
I have a sub-question. In the case I have a bean: ThingFacade and I inject the same bean into it.... @EJB ThingFacade thingFacade; by invoking one ThingFacade method throught the thingFacade reference from another method in thingFacade, am I going to go throught the proxy... or not?Grandiloquence
Yes, you are going through the proxy if you inject a reference to the same EJBLucy
P
23

inject SessionContext, and ask it for your proxy instance:

@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();
    }
}

in 'invocation#1' this is a Local call, not passing through proxy, it will return the count

in 'invocation#2' this is a call through the proxy, and hence you annotate it not to support transaction -which is now opened by create(user) method-, this invocation will throw a transaction exception:

javax.ejb.EJBException: EJB cannot be invoked in global transaction

Programme answered 8/9, 2012 at 12:11 Comment(2)
Interesting hack, i am wondering if there any overall disadvantages from doing this apart from been inconsistent with the general consensus that EJB and Spring work through transactional proxies and thus transaction annotations etc. are ignored in local method calls, which obviously affects the designAnn
@nvrs, this was just a code i used to know how proxies work, but I don't know how it could be used in real life.Programme
A
4

They will use the same transaction.

If I remember well, the transaction is started by the container "before" the method is invoked and commited after it "finish".

Since "a" calls "b", "b" would use the same transaction.

:S

I guess the best thing you can do is test it to verify it! :)

Attwood answered 9/1, 2009 at 9:22 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.