EntityBean ejbCreate() transaction problems

Discussions

EJB design: EntityBean ejbCreate() transaction problems

  1. EntityBean ejbCreate() transaction problems (11 messages)

    Just find out some interesting things about the transaction handling of the ejbCreate() method of EntityBeans. The result

    is: if you want to make ejbCreate() itself to be a single working unit, you must wrap it with a Session Bean.

    Platform: Weblogic 5.10 sp8, ejb 1.1
    Scenario:

    Suppose we have two entity beans: Order and LineItem with 1:n relationship. We want to creat LineItems inside the

    ejbCreate() method of Order. In deployment descriptor, both Order and LineItem are using Container Managed Transaction, with

    all methods "TX_Required".


    1.
    Order.ejbCreate(DeepData data) throws CreateException, RemoteException{
    id = data.getId(); // id the PK of Order
    price = data.getPrice();
    ... // create Order itself

    createLineItems();
    }

    2. then we have a normal java class as client, not transaction aware at all:

    try{
    OrderHome.create(deepData);
    }catch(CreateException e){
    System.out.println(e);
    }

    3. inside deepData, we give Order data object an existing id (PK) on purpose, guess the result?

    4. the result is: Client gets a CreateException (DuplicateKeyException), of course Order has not been created; but,

    LineItems have been created in the DB.

    5. Reason, ref to Chapter 12.3.1 in ejb-1.1-spec from Sun
    * Since all Order methods are TX_Required, Container will start a new tx for Order.create()
    * create Order first (set value only), then create LineItems, not error yet
    * when write to DB, container found PK of Order duplicated, it throws a CreateException
    * CreateException is an Application Exception, not a run-time exception, based upon Spec, Container will try to

    commit the transaction, then throw the Exception out to Client
    * though an Exception is thrown, the whole transaction has been committed, cause only RunTime exception will auto

    rollback the transaction, like RemoteException, EJBException

    6. Of course, this kind of result is not we want, so, when we want to create Order with deep data, we have to go through a

    SessionBean's method (TX_Required)

    try{
    OrderHome.create(deepData);
    }catch(CreateException e){
    ctx.setRollBackOnly();
    throw new Exception();
    // or directly throw a RemoteException, without say ctx.setRollbackOnly();
    }

    My feeling is, ejbCreate() should throw a RemoteException or EJBException instead of CreateException when DuplicateKey such

    kind of things happen.

    Maybe this pattern will also affect ejbRemove(), but i did not test it yet.

  2. Just a follow-up, my friend tested it in Websphere 3.5, exactly the same behavior. We will test it in jBoss and Weblogic 6 soon.
  3. Is Order a CMP bean? I mean who is throwing the CreateException? You say the container is throwing it, but this would only be true in CMP right? If this was BMP it would be your job to throw the right exception or, simply mark the component for rollback. So can I assume from your statement that this is a CMP bean?

    Dave Wolf
    Internet Applications Division
    Sybase
  4. Your Order.ejbCreate() should intercept OrderItem's CreateException and throw an EJBException.
  5. All entities in my examples are CMP Beans, sorry, forgot to mention it.

    And, catch CreateException for create LineItems in Order does not help, cause it is Order has DuplicateKey, not LineItem. So, LineItem will be created successfully, but finally Order throws an DuplicateKeyException.
  6. From design point of view, it is better to move your lineItem EB creation logic to the upper session bean,
    since they are seperate entity beans.
    If you want to let Order to control the life cycle of
    LineItem, LineItem probably should not be entity bean
    himself.
  7. 1. I think it is very important for Order to control LineItem's lifecycle. Put this logic into a SessionBean may not be a good idea.

    2. If LineItem is not a EntityBean, but a Dependent Object of Order, I got what you mean, I can make LineItem a serialized object store as a field of Order, but this is real world, we need a table LineItem in the database cause we need create views, do summary SQL, and generate report.

    3. For ejb2, I tested its Dependent Object stuff in Weblogic 6, at first it works fine, but, it does not support Cascade Delete (though spec says it should, but i did not find how to do it in WLS6). And also maybe this problem still exsits, let me try it
  8. Exactly,LineItem is a dependent object of Order,store
    in a seperate table.
    The container has no reason to commit only part of the bean:-)
  9. I tried in Weblogic 6 SP1. Something interesting:

    1. if use EJB2.0 CMR, when i want to associate LineItem with Order, i must first create and get the remote interface of LineItem, then associate it with Order. That is simliar to wrap the relationship with a SessionBean. Of course it is fine.

    2. WLS 6 does not support Cascade Delete right now in EJB 2.0 CMR, it will be working in their next minor release.

    3. When i test my old code (EJB1.1, maintain relationship through ejbCreate(), ejbRemove()), WLS gives strange behaviors (about ejbCreate() overload), so the test failed to go on. But one thing is sure, though there is CreateException in the parent Entity, TX still is committed, so the LineItems are created. Same behavior.

    4. WLS 6 ejbCreate() overload problem: inside one ejbCreate() i call antoher ejbCreate() first, seems WLS 6 tries to commit both of ejbCreate(), so i always get DuplicateKeyException. It works fine in WLS 5.1, and i generated fresh new jars in wls 6.
  10. The answer is to use the oft-forgotten ejbPostCreate(). You don't want to create the line items until the order has been created:

    // Order.java
    public <throws CreateException {
      <  return null;
    }

    public void ejbPostCreate(DeepData data)
    throws CreateException {
      try {
        createLineItems(data.getLineItems());
      }
      catch (CreateException e) {
        // If we can't create one of the line items,
        // roll back the entire transaction
        context.setRollbackOnly();
        throw e;
      }
    }

    --Steven
  11. Thanks. However, there still is problems.

     Yes, ejbCreate() and ejbPostCreate() must be in the same TX. You can
    be sure that if there is a CreateException in LineItem, the whole Tx
    will be rollbacked.

    But we do not know when will the Container throws out CreateException,
    inside ejbCreate(), or after ejbPostCreate(). I guess it really
    depends on the Container. When container calls ejbPostCreate() does
    not necessarliry mean that the Order has no problem at all or it is
    already created.

    From ejb1.1-spec, page 132:
    "The Container must establish the primary key before it invokes the
    ejbPostCreate(...) method. The container may create the representation
    of the entity in the database immediately after ejbCreate(...)
    returns, or it can defer it to a later time (for example to the time
    after the matching ejbPostCreate(...) has been called, or to the end
    of the transaction)."

    My guess is in different Container the impl is different. If the
    container is smart, it should check if there is DuplicatePrimaryKey in
    ejbCreate() and reserve it (but how?), then persistent the entity
    before or after ejbPostCreate(). But there is no gurrantee. If
    Container gets a CreateException after calling ejbPostCreate(), as i
    said before, the whole tx still will be committed, with LineItems
    created without Order.
  12. Hello :-)

    I think the point is if you treat line item as Entity bean,
    then you CANNOT create it INSIDE order bean create method.

    From API point of view, it doesn't work because DuplicatedKey is an applicatin exception.

    From semantic point of view, it doesn't make sense because the atomic of order bean's ejbCreate method is broken,
    such relationship should be handled by upper session bean or
    in order bean's business method.