3 Replies Latest reply on Jan 7, 2008 1:15 PM by branez

    Bean method called from within transaction cannot open conne

    branez

      Context: JBoss 4.0.5 , EJB Container-managed transactions, local MySQL db

      I started out doing this using BMT but since I have no need for custom handling of transaction, I thought I would switch to CMT. In the code below, I have some pretty basic functions. I can and do call find() directly and it works fine. The problem occurs when I have the case of a duplicate entry and I enter the EntityExistsException's catch block. When the find() within that catch block is called, getSingleResult() in find() throws a GenericJDBCException stating that a connection cannot be opened, which in turn is caused by a "Transaction is inactive" problem.

      CMTBean provides the injected entitymanager reference.

      What happens to the transaction in the catch block that causes find() (which is by default of the REQUIRED transaction policy) to lose the connection? EntityExistsException does not cause a rollback and even if it did, find() would start its own transaction, would it not?

      Your prompt responses are appreciated.

      @Stateless
      @TransactionAttribute(TransactionAttributeType.REQUIRED)
      public class MyBean extends CMTBean implements MyBeanLocal{
      
       public List<Item> addItems(List<Item> items) {
       List<Item> mergedList = new ArrayList<Item>();
       for(Item item:items){
      
       //Call another bean method
       mergedList.add(addItem(item));
      
       }
       return mergedList;
       }
      
       public Item addItem(Item item){
       try{
       item = em.merge(item);
       }
       catch (EntityExistsException ex){
      
       //Since item exists, call another bean method to retrieve it
       item = find(item.getName());
      
       }
       return item;
       }
      
       public Item find(String name){
       Query query = null;
       Item item = null;
      
       try {
       query = em.createQuery("SELECT it FROM Item it WHERE it.name=:name");
       query = query.setParameter("name", name);
      
       // GenericJDBCException thrown here - "Cannot open connection."
       item = (Item) query.getSingleResult();
      
       }
       catch (...)
       //error handling
       }
       return item;
       }
      }
      


      The pertinent parts of the stacktrace:

      17:17:26,874 ERROR [JDBCExceptionReporter] Transaction is not active: tx=TransactionImpl:XidImpl[FormatId=257, GlobalId=local/24, BranchQual=, localId=24]; - nested throwable: (javax.resource.ResourceException: Transaction is not active: tx=TransactionImpl:XidImpl[FormatId=257, GlobalId=local/24, BranchQual=, localId=24])
      17:17:26,905 ERROR [STDERR] Exception in thread "Thread-28"
      17:17:26,905 ERROR [STDERR] javax.ejb.EJBException: javax.persistence.PersistenceException: org.hibernate.exception.GenericJDBCException: Cannot open connection
      17:17:26,905 ERROR [STDERR] at org.jboss.ejb3.tx.Ejb3TxPolicy.handleExceptionInOurTx(Ejb3TxPolicy.java:69)
      17:17:26,905 ERROR [STDERR] at org.jboss.aspects.tx.TxPolicy.invokeInOurTx(TxPolicy.java:83)
      17:17:26,905 ERROR [STDERR] at org.jboss.aspects.tx.TxInterceptor$Required.invoke(TxInterceptor.java:191)
      17:17:26,905 ERROR [STDERR] at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:101)
      17:17:26,905 ERROR [STDERR] at org.jboss.aspects.tx.TxPropagationInterceptor.invoke(TxPropagationInterceptor.java:76)
      17:17:26,905 ERROR [STDERR] at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:101)
      17:17:26,905 ERROR [STDERR] at org.jboss.ejb3.stateless.StatelessInstanceInterceptor.invoke(StatelessInstanceInterceptor.java:62)
      17:17:26,905 ERROR [STDERR] at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:101)
      17:17:26,905 ERROR [STDERR] at org.jboss.aspects.security.AuthenticationInterceptor.invoke(AuthenticationInterceptor.java:77)
      17:17:26,905 ERROR [STDERR] at org.jboss.ejb3.security.Ejb3AuthenticationInterceptor.invoke(Ejb3AuthenticationInterceptor.java:102)
      17:17:26,905 ERROR [STDERR] at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:101)
      17:17:26,905 ERROR [STDERR] at org.jboss.ejb3.ENCPropagationInterceptor.invoke(ENCPropagationInterceptor.java:47)
      17:17:26,905 ERROR [STDERR] at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:101)
      17:17:26,905 ERROR [STDERR] at org.jboss.ejb3.asynchronous.AsynchronousInterceptor.invoke(AsynchronousInterceptor.java:106)
      17:17:26,905 ERROR [STDERR] at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:101)
      17:17:26,905 ERROR [STDERR] at org.jboss.ejb3.stateless.StatelessContainer.localInvoke(StatelessContainer.java:211)
      17:17:26,905 ERROR [STDERR] at org.jboss.ejb3.stateless.StatelessLocalProxy.invoke(StatelessLocalProxy.java:79)
      17:17:26,905 ERROR [STDERR] at $Proxy85.addRootItems(Unknown Source)
      17:17:26,905 ERROR [STDERR] at commit(ServerScanner.java:171)
      17:17:26,905 ERROR [STDERR] at CommitThread.run(CommitThread.java:163)
      17:17:26,905 ERROR [STDERR] Caused by: javax.persistence.PersistenceException: org.hibernate.exception.GenericJDBCException: Cannot open connection
      17:17:26,905 ERROR [STDERR] at org.hibernate.ejb.AbstractEntityManagerImpl.throwPersistenceException(AbstractEntityManagerImpl.java:647)
      17:17:26,905 ERROR [STDERR] at org.hibernate.ejb.QueryImpl.getSingleResult(QueryImpl.java:99)
      17:17:26,905 ERROR [STDERR] at MyBean.findUrl(MyBean.java:112)
      17:17:26,905 ERROR [STDERR] at MyBean.addRootItem(MyBean.java:51)
      17:17:26,905 ERROR [STDERR] at MyBean.addRootItems(MyBean.java:90)
      17:17:26,905 ERROR [STDERR] at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
      17:17:26,905 ERROR [STDERR] at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
      17:17:26,905 ERROR [STDERR] at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
      17:17:26,905 ERROR [STDERR] at java.lang.reflect.Method.invoke(Method.java:585)
      17:17:26,921 ERROR [STDERR] at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:112)
      17:17:26,921 ERROR [STDERR] at org.jboss.ejb3.interceptor.InvocationContextImpl.proceed(InvocationContextImpl.java:166)
      17:17:26,921 ERROR [STDERR] at org.jboss.ejb3.interceptor.EJB3InterceptorsInterceptor.invoke(EJB3InterceptorsInterceptor.java:63)
      17:17:26,921 ERROR [STDERR] at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:101)
      17:17:26,921 ERROR [STDERR] at org.jboss.ejb3.entity.TransactionScopedEntityManagerInterceptor.invoke(TransactionScopedEntityManagerInterceptor.java:54)
      17:17:26,921 ERROR [STDERR] at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:101)
      17:17:26,921 ERROR [STDERR] at org.jboss.ejb3.AllowedOperationsInterceptor.invoke(AllowedOperationsInterceptor.java:46)
      17:17:26,921 ERROR [STDERR] at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:101)
      17:17:26,921 ERROR [STDERR] at org.jboss.aspects.tx.TxPolicy.invokeInOurTx(TxPolicy.java:79)
      17:17:26,921 ERROR [STDERR] ... 18 more
      17:17:26,921 ERROR [STDERR] Caused by: org.hibernate.exception.GenericJDBCException: Cannot open connection
      17:17:26,921 ERROR [STDERR] at org.hibernate.exception.SQLStateConverter.handledNonSpecificException(SQLStateConverter.java:103)
      17:17:26,921 ERROR [STDERR] at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:91)
      17:17:26,921 ERROR [STDERR] at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:43)
      17:17:26,921 ERROR [STDERR] at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:29)
      17:17:26,921 ERROR [STDERR] at org.hibernate.jdbc.ConnectionManager.openConnection(ConnectionManager.java:420)
      17:17:26,921 ERROR [STDERR] at org.hibernate.jdbc.ConnectionManager.getConnection(ConnectionManager.java:144)
      17:17:26,921 ERROR [STDERR] at org.hibernate.jdbc.AbstractBatcher.prepareQueryStatement(AbstractBatcher.java:139)
      17:17:26,921 ERROR [STDERR] at org.hibernate.loader.Loader.prepareQueryStatement(Loader.java:1560)
      17:17:26,921 ERROR [STDERR] at org.hibernate.loader.Loader.doQuery(Loader.java:661)
      17:17:26,921 ERROR [STDERR] at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:224)
      17:17:26,921 ERROR [STDERR] at org.hibernate.loader.Loader.doList(Loader.java:2144)
      17:17:26,921 ERROR [STDERR] at org.hibernate.loader.Loader.listIgnoreQueryCache(Loader.java:2028)
      17:17:26,921 ERROR [STDERR] at org.hibernate.loader.Loader.list(Loader.java:2023)
      17:17:26,921 ERROR [STDERR] at org.hibernate.loader.hql.QueryLoader.list(QueryLoader.java:393)
      17:17:26,921 ERROR [STDERR] at org.hibernate.hql.ast.QueryTranslatorImpl.list(QueryTranslatorImpl.java:338)
      17:17:26,921 ERROR [STDERR] at org.hibernate.engine.query.HQLQueryPlan.performList(HQLQueryPlan.java:172)
      17:17:26,921 ERROR [STDERR] at org.hibernate.impl.SessionImpl.list(SessionImpl.java:1121)
      17:17:26,921 ERROR [STDERR] at org.hibernate.impl.QueryImpl.list(QueryImpl.java:79)
      17:17:26,921 ERROR [STDERR] at org.hibernate.ejb.QueryImpl.getSingleResult(QueryImpl.java:80)
      17:17:26,921 ERROR [STDERR] ... 34 more
      17:17:26,921 ERROR [STDERR] Caused by: org.jboss.util.NestedSQLException: Transaction is not active: tx=TransactionImpl:XidImpl[FormatId=257, GlobalId=local/24, BranchQual=, localId=24]; - nested throwable: (javax.resource.ResourceException: Transaction is not active: tx=TransactionImpl:XidImpl[FormatId=257, GlobalId=local/24, BranchQual=, localId=24])
      17:17:26,921 ERROR [STDERR] at org.jboss.resource.adapter.jdbc.WrapperDataSource.getConnection(WrapperDataSource.java:94)
      17:17:26,921 ERROR [STDERR] at org.hibernate.ejb.connection.InjectedDataSourceConnectionProvider.getConnection(InjectedDataSourceConnectionProvider.java:47)
      17:17:26,921 ERROR [STDERR] at org.hibernate.jdbc.ConnectionManager.openConnection(ConnectionManager.java:417)
      17:17:26,921 ERROR [STDERR] ... 48 more
      17:17:26,921 ERROR [STDERR] Caused by: javax.resource.ResourceException: Transaction is not active: tx=TransactionImpl:XidImpl[FormatId=257, GlobalId=local/24, BranchQual=, localId=24]
      17:17:26,921 ERROR [STDERR] at org.jboss.resource.connectionmanager.TxConnectionManager.getManagedConnection(TxConnectionManager.java:290)
      17:17:26,921 ERROR [STDERR] at org.jboss.resource.connectionmanager.BaseConnectionManager2.allocateConnection(BaseConnectionManager2.java:396)
      17:17:26,921 ERROR [STDERR] at org.jboss.resource.connectionmanager.BaseConnectionManager2$ConnectionManagerProxy.allocateConnection(BaseConnectionManager2.java:842)
      17:17:26,921 ERROR [STDERR] at org.jboss.resource.adapter.jdbc.WrapperDataSource.getConnection(WrapperDataSource.java:88)
      17:17:26,921 ERROR [STDERR] ... 50 more

        • 1. Re: Bean method called from within transaction cannot open c
          jaikiran

          Does merge actually throw a EntityExistsException? The javadoc does not mention this. Or is this code, that you posted, just for outlining the behaviour?

          EntityExistsException does not cause a rollback and even if it did, find() would start its own transaction, would it not?


          I would believe that the transaction would not be rolled back(or set to INACTIVE state) when the exception occurs within the bean. However calling the find method from within the catch block is not going to create a transaction. If you have to start a transaction when the find method is called then you will have to get access to the ejb object in the catch block and then call the find method on it.

          • 2. Re: Bean method called from within transaction cannot open c
            branez

            Yes, the merge() detects that item is a not a detached entity and attempts to persist it, and this in turn fails because there is a unique constraint on the name field.

            By EJB object do you mean the EJBContext? find() is supposed to fetch the existing entry. It is using the same object that would have been persisted in the database to get name and then pass that to find().

            (Sorry I chose a poor name for this example, but find() is what I posted above and is not EntityManager.find() )

            • 3. Re: Bean method called from within transaction cannot open c
              branez

              Problem solved. The error handling in this case could not be accomplished by catching EntityExistsException, since PersistenceExceptions except for NoResultException and NonUniqueException mark the transaction for rollback, causing it to be unavailable for the next iteration of addRootItem(). The existence check had to come first and, if it doesn't exist, Query.getSingleResult() throws NoResultException, which can then be handled properly because it does not cause a transaction rollback.