5 Replies Latest reply on May 21, 2007 2:58 AM by amitka

    Transaction annotation - cannot get desired behavior

    lpmon

      JBoss 4.0.5 (em = injected entitymanger in text below)

      Need a way to prevent an EntityExistsException from stopping processing (kills DB connection).

      Root problem:
      In a loop callimg em.persist(obj);
      After an EntityExistsException is thrown I get the following trying to continue in the same method.

      20:35:40,265 WARN [JDBCExceptionReporter] SQL Error: 0, SQLState: null
      20:35:40,265 ERROR [JDBCExceptionReporter] Transaction is not active: tx=TransactionImpl:XidImpl[FormatId=257, GlobalId=w2ksvr/10, BranchQual=, localId=10]; - nested throwable: (javax.resource.ResourceException: Transaction is not active: tx=TransactionImpl:XidImpl[FormatId=257, GlobalId=w2ksvr/10, BranchQual=, localId=10])

      After some reading I found the transaction is marked for rollback due to the exception.

      So I moved the persist call into a method that has
      @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)

      This does not seem to have any affect. In fact the inserts that are being done in each call to the method (with no exception) are not committed to the DB until to top method in the call stack exits. I though that the REQUIRES_NEW annotation should force the commit of the transaction at the end of the method that it applies to???????

      My server call stack is:

      session bean-1 calls
      session bean-2 method that does DB work

      It appears the commit does not occur until the session bean-1 method exits. Ideas? Have I understood how the annotation is supposed to work?

      em calls from either bean report 'Cannot open connection' on subsequent em calls

        • 1. Re: Transaction annotation - cannot get desired behavior
          lpmon

          Surely someone has a hint on this. My experience is the transaction annotations have no effect. -OR- I have misinterpreted something.

          My experience: no transactions are committed unless the method in the top session bean in the call chain exits.

          My understanding:

          A method annotated with:

          @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)

          would commit upon method exit. (not happening)

          Shouldn't this start a new transaction and commit upon exit????

          • 2. Re: Transaction annotation - cannot get desired behavior

            One way to solve it, from my experience, would be to inject another instance of that bean to itself, and invoke the method (the one annotated with REQUIRES_NEW) on that injected bean. Otherwise the transaction attributes annotations have no effect because you're not working with the proxy but with the class itself.

            i.e.

            @Stateless public class YourBean impelemts YourBeanLocal {
            
             @EJB YourBeanLocal yourBean;
            
             public void callingMethod() {
             ...
             yourBean.yourRequiresNewMethod(...);
             ...
             }
            
             @TransactionAttribute(...REQUIRES_NEW) yourRequiresNewMethod() {
             ...
             }
            }
            


            This does have a problem that whenever using this bean you're actually acquiring 2 instances of it.

            If you think of a better way to do it, I'll be very glad to know.

            HTH.

            • 3. Re: Transaction annotation - cannot get desired behavior
              waynebaylor

              Here's an alternative:

              Instead of trying to ignore the exception, try calling em.contains(...) and if that returns false, then execute em.persist(...).

              • 4. Re: Transaction annotation - cannot get desired behavior
                waynebaylor

                Even better, try using em.merge(...) instead of em.persist(...). That way if the entity exists it will be merged and you won't get an exception.

                • 5. Re: Transaction annotation - cannot get desired behavior

                  This will only work for EntityExistsException due to primary key constraint. The situation I encountered is with a unique constraint on other columns which are not primary keys.

                  I used the setter methods to set some field values, and then handled both InvalidStateException to retrieve all of the InvalidValue-s, and EntityExistsException to know if a unique constraint has been violated. The problem is that in the catch block of the EntityExistsException, I couldn't query and extract which field's uniqueness the update tried to violate. The only solution I did find was to receive another instance of the (same) bean (from itself), and invoke a REQUIRES_NEW method on that other instance which does the query.