5 Replies Latest reply on Jun 1, 2004 8:44 AM by cwoodill

    Problem with rolling back transactions with JBoss 3.2.3 and

    cwoodill

      I'm setting up MySQL with JBoss and testing the transaction facility. I have a stateless session bean that I have created using the JBoss IDE. Everything works without an error.

      At the DB level, the transactions fail properly - INNODB is setup, and I roll-back properly through SQL.

      I'm using the standard mysql-ds.xml datasource. It is a local-tx datasource, so it should be transaction enabled.

      When I access the session bean, if the second table insert fails, it should rollback. However, it doesn't seem to be doing that - the first table record still gets inserted. In addition, if I just throw an EJB exception, it fails to roll-back as well.

      Code is at the end of the message. This is dummy code, just proof of concept stuff. I have two tables in the same datasource, and I'm inserting test records in both. I have assigned a primary key to the second table so that if I try to access it twice, the second table insert will fail (which it does).

      Thanks.


      /*
       * Created on Mar 7, 2004
       *
       * To change the template for this generated file go to
       * Window>Preferences>Java>Code Generation>Code and Comments
       */
      package tutorial.ejb;
      
      import javax.ejb.*;
      import java.rmi.RemoteException;
      import java.sql.*;
      import javax.transaction.*;
      import javax.naming.*;
      import javax.sql.DataSource;
      
      
      /**
       * @ejb.bean description="Stateless Session Bean that computes fibonacci"
       * display-name="Fibo EJB"
       * jndi-name="ejb/tutorial/Fibo"
       * name="Fibo"
       * type="Stateless"
       * view-type="remote"
       * transaction-type="Bean"
       *
       */
      
      public class FiboBean implements SessionBean {
      
      
       private SessionContext context;
       private Connection con;
       private String dbName = "java:/jdbc/mysql-eCity";
      
       /**
       * Default Create Method
       * @throws CreateException
       * @ejb.create-method
       *
       */
      
       public void ejbCreate() throws CreateException
       {
       try {
       makeConnection();
       } catch (Exception ex) {
       throw new CreateException(ex.getMessage());
       }
       }
      
       /**
       * @param number
       * @return
       *
       * @ejb.interface-method view-type="remote"
       *
       */
      
       public double[] compute(int number)
       {
      
       UserTransaction ut = context.getUserTransaction();
      
       try {
       ut.begin();
       insertTable1();
       if (number == 4)
       throw new Exception("testing");
       insertTable2();
       ut.commit();
       } catch (Exception ex) {
       try {
       ut.rollback();
       } catch (SystemException syex) {
       throw new EJBException
       ("Rollback failed: " + syex.getMessage());
       }
      
       try
       {
       System.out.println("Rollback and Closing connection");
       con.close();
       throw new EJBException
       ("Transaction failed: " + ex.getMessage());
       }
       catch (SQLException e)
       {
       throw new EJBException
       ("Failed to close connection: " + e.getMessage());
       }
      
      
      
       }
      
       if (number < 0)
       throw new EJBException("Argument should be positive.");
       double suite[] = new double[number + 1];
       suite[0]=0;
       suite[1]=1;
       for (int i=2; i<= number; i++)
       {
       suite = suite[i-1] + suite[i-2];
       }
       return suite;
       }
      
       public void insertTable1() throws SQLException
       {
       String updateStatement =
       "insert into test values (?)";
      
       PreparedStatement prepStmt =
       con.prepareStatement(updateStatement);
      
       prepStmt.setString(1, "test1");
       prepStmt.executeUpdate();
       prepStmt.close();
       }
      
       public void insertTable2() throws SQLException
       {
       String updateStatement =
       "insert into test2 values (?)";
      
       PreparedStatement prepStmt =
       con.prepareStatement(updateStatement);
      
       prepStmt.setString(1, "test2");
       prepStmt.executeUpdate();
       prepStmt.close();
      
       }
      
       private void makeConnection()
       throws NamingException, SQLException {
      
       InitialContext ic = new InitialContext();
       DataSource ds = (DataSource) ic.lookup(dbName);
       con = ds.getConnection();
       }
      
       public void ejbActivate() throws EJBException, RemoteException{
       }
      
       public void ejbPassivate() throws EJBException, RemoteException{
       }
      
       public void ejbRemove() throws EJBException, RemoteException{
       try
       {
       System.out.println("closing connection");
       con.close();
       }
       catch (SQLException e)
       {
       throw new EJBException(e);
       }
      
       }
      
       public void setSessionContext(SessionContext context) throws EJBException, RemoteException{
       this.context = context;
       }
       }



        • 1. Re: Problem with rolling back transactions with JBoss 3.2.3

          Read "READ THIS FIRST" on how to debug transaction problems.
          You might also find it useful to set TRACE loggin on org.jboss.ejb.plugins

          Throwing Exception does not cause a transaction rollback.

          Exiting a method without doing a commit() or rollback() on your user transaction
          is an error on your part that JBoss should warn you about.

          Allocating connections in ejbCreate is a inefficent use of resources.

          • 2. Re: Problem with rolling back transactions with JBoss 3.2.3
            cwoodill

            Thanks for the quickly reply. I put on the tracing as recommended and here is the rollback section:

            2004-05-19 14:19:36,814 TRACE [org.jboss.resource.connectionmanager.JBossManagedConnectionPool] supplying ManagedConnection from pool: org.jboss.resource.adapter.jdbc.local.LocalManagedConnection@fa0d1
            2004-05-19 14:19:36,814 TRACE [org.jboss.resource.connectionmanager.JBossManagedConnectionPool] Getting connection from pool [InUse/Available/Max]: [1/3/20]
            2004-05-19 14:19:36,814 TRACE [org.jboss.resource.connectionmanager.CachedConnectionManager] registering connection from org.jboss.resource.connectionmanager.TxConnectionManager@36ae83, connection : org.jboss.resource.adapter.jdbc.WrappedConnection@706f6, key: null
            2004-05-19 14:19:36,814 TRACE [org.jboss.resource.connectionmanager.CachedConnectionManager] new stack for key: tutorial.ejb.FiboBean@dd4c8
            2004-05-19 14:19:36,824 TRACE [org.jboss.tm.TxManager] tx timeout is now: 0s
            2004-05-19 14:19:36,824 TRACE [org.jboss.tm.TransactionImpl] Created new instance for tx=TransactionImpl:XidImpl [FormatId=257, GlobalId=kelly//19, BranchQual=]
            2004-05-19 14:19:36,824 TRACE [org.jboss.tm.TxManager] began tx: TransactionImpl:XidImpl [FormatId=257, GlobalId=kelly//19, BranchQual=]
            2004-05-19 14:19:36,824 TRACE [org.jboss.resource.connectionmanager.CachedConnectionManager] user tx started, key: org.jboss.resource.connectionmanager.CachedConnectionManager$KeyConnectionAssociation@dd4c8
            2004-05-19 14:19:36,904 TRACE [org.jboss.tm.TransactionImpl] rollback(): Entered, tx=TransactionImpl:XidImpl [FormatId=257, GlobalId=kelly//19, BranchQual=] status=STATUS_ACTIVE
            2004-05-19 14:19:36,904 TRACE [org.jboss.tm.TxManager] rolled back tx: TransactionImpl:XidImpl [FormatId=257, GlobalId=kelly//19, BranchQual=]
            2004-05-19 14:19:36,904 INFO [STDOUT] Rollback and Closing connection
            2004-05-19 14:19:36,904 TRACE [org.jboss.resource.connectionmanager.TxConnectionManager] connectionClosed called
            2004-05-19 14:19:36,904 TRACE [org.jboss.resource.connectionmanager.CachedConnectionManager] unregistering connection from org.jboss.resource.connectionmanager.TxConnectionManager@36ae83, object: org.jboss.resource.adapter.jdbc.WrappedConnection@706f6, key: org.jboss.resource.connectionmanager.CachedConnectionManager$KeyConnectionAssociation@dd4c8
            2004-05-19 14:19:36,904 TRACE [org.jboss.resource.connectionmanager.TxConnectionManager] unregisterConnection: 0 handles left
            2004-05-19 14:19:36,904 TRACE [org.jboss.resource.connectionmanager.TxConnectionManager] delisting currenttx: null, ManagedConnection: org.jboss.resource.adapter.jdbc.local.LocalManagedConnection@fa0d1
            2004-05-19 14:19:36,904 TRACE [org.jboss.resource.connectionmanager.JBossManagedConnectionPool] putting ManagedConnection back into pool
            2004-05-19 14:19:36,904 TRACE [org.jboss.resource.connectionmanager.JBossManagedConnectionPool] Returning connection to pool [InUse/Available/Max]: [0/3/20]
            2004-05-19 14:19:36,904 TRACE [org.jboss.resource.connectionmanager.CachedConnectionManager] popped object: org.jboss.resource.connectionmanager.CachedConnectionManager$KeyConnectionAssociation@dd4c8
            2004-05-19 14:19:36,904 INFO [STDOUT] closing connection
            2004-05-19 14:19:36,904 ERROR [org.jboss.ejb.plugins.LogInterceptor] EJBException:
            javax.ejb.EJBException: Transaction failed: Invalid argument value, message from server: "Duplicate entry 'test2' for key 1"
            at tutorial.ejb.FiboBean.compute(FiboBean.java:82)
            at java.lang.reflect.Method.invoke(Native Method)
            at org.jboss.ejb.StatelessSessionContainer$ContainerInterceptor.invoke(StatelessSessionContainer.java:683)
            at org.jboss.resource.connectionmanager.CachedConnectionInterceptor.invoke(CachedConnectionInterceptor.java:185)
            at org.jboss.ejb.plugins.AbstractTxInterceptor.invokeNext(AbstractTxInterceptor.java:84)
            at org.jboss.ejb.plugins.AbstractTxInterceptorBMT.invokeNext(AbstractTxInterceptorBMT.java:144)
            at org.jboss.ejb.plugins.TxInterceptorBMT.invoke(TxInterceptorBMT.java:62)
            at org.jboss.ejb.plugins.StatelessSessionInstanceInterceptor.invoke(StatelessSessionInstanceInterceptor.java:72)
            at org.jboss.ejb.plugins.SecurityInterceptor.invoke(SecurityInterceptor.java:118)
            at org.jboss.ejb.plugins.LogInterceptor.invoke(LogInterceptor.java:191)
            at org.jboss.ejb.plugins.ProxyFactoryFinderInterceptor.invoke(ProxyFactoryFinderInterceptor.java:122)
            at org.jboss.ejb.StatelessSessionContainer.internalInvoke(StatelessSessionContainer.java:331)
            at org.jboss.ejb.Container.invoke(Container.java:700)
            at java.lang.reflect.Method.invoke(Native Method)
            at org.jboss.mx.capability.ReflectedMBeanDispatcher.invoke(ReflectedMBeanDispatcher.java:284)
            at org.jboss.mx.server.MBeanServerImpl.invoke(MBeanServerImpl.java:546)
            at org.jboss.invocation.local.LocalInvoker.invoke(LocalInvoker.java:101)
            at org.jboss.invocation.InvokerInterceptor.invoke(InvokerInterceptor.java:90)
            at org.jboss.proxy.TransactionInterceptor.invoke(TransactionInterceptor.java:46)
            at org.jboss.proxy.SecurityInterceptor.invoke(SecurityInterceptor.java:45)
            at org.jboss.proxy.ejb.StatelessSessionInterceptor.invoke(StatelessSessionInterceptor.java:100)
            at org.jboss.proxy.ClientContainer.invoke(ClientContainer.java:85)
            at $Proxy33.compute(Unknown Source)
            at tutorial.web.ComputeServlet.doPost(ComputeServlet.java:88)
            at javax.servlet.http.HttpServlet.service(HttpServlet.java:760)
            at javax.servlet.http.HttpServlet.service(HttpServlet.java:853)
            at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:247)
            at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:193)
            at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:256)
            at org.apache.catalina.core.StandardPipeline$StandardPipelineValveContext.invokeNext(StandardPipeline.java:643)
            at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:480)
            at org.apache.catalina.core.ContainerBase.invoke(ContainerBase.java:995)
            at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191)
            at org.apache.catalina.core.StandardPipeline$StandardPipelineValveContext.invokeNext(StandardPipeline.java:643)
            at org.jboss.web.tomcat.security.JBossSecurityMgrRealm.invoke(JBossSecurityMgrRealm.java:220)
            at org.apache.catalina.core.StandardPipeline$StandardPipelineValveContext.invokeNext(StandardPipeline.java:641)
            at org.apache.catalina.valves.CertificatesValve.invoke(CertificatesValve.java:246)
            at org.apache.catalina.core.StandardPipeline$StandardPipelineValveContext.invokeNext(StandardPipeline.java:641)
            at org.jboss.web.tomcat.tc4.statistics.ContainerStatsValve.invoke(ContainerStatsValve.java:76)
            at org.apache.catalina.core.StandardPipeline$StandardPipelineValveContext.invokeNext(StandardPipeline.java:641)
            at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:480)
            at org.apache.catalina.core.ContainerBase.invoke(ContainerBase.java:995)
            at org.apache.catalina.core.StandardContext.invoke(StandardContext.java:2417)
            at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:180)
            at org.apache.catalina.core.StandardPipeline$StandardPipelineValveContext.invokeNext(StandardPipeline.java:643)
            at org.apache.catalina.valves.ErrorDispatcherValve.invoke(ErrorDispatcherValve.java:171)
            at org.apache.catalina.core.StandardPipeline$StandardPipelineValveContext.invokeNext(StandardPipeline.java:641)
            at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:172)
            at org.apache.catalina.core.StandardPipeline$StandardPipelineValveContext.invokeNext(StandardPipeline.java:641)
            at org.jboss.web.tomcat.security.SecurityAssociationValve.invoke(SecurityAssociationValve.java:65)
            at org.apache.catalina.core.StandardPipeline$StandardPipelineValveContext.invokeNext(StandardPipeline.java:641)
            at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:577)
            at org.apache.catalina.core.StandardPipeline$StandardPipelineValveContext.invokeNext(StandardPipeline.java:641)
            at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:480)
            at org.apache.catalina.core.ContainerBase.invoke(ContainerBase.java:995)
            at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:174)
            at org.apache.catalina.core.StandardPipeline$StandardPipelineValveContext.invokeNext(StandardPipeline.java:643)
            at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:480)
            at org.apache.catalina.core.ContainerBase.invoke(ContainerBase.java:995)
            at org.apache.coyote.tomcat4.CoyoteAdapter.service(CoyoteAdapter.java:197)
            at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:781)
            at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.processConnection(Http11Protocol.java:549)
            at org.apache.tomcat.util.net.TcpWorkerThread.runIt(PoolTcpEndpoint.java:605)
            at org.apache.tomcat.util.threads.ThreadPool$ControlRunnable.run(ThreadPool.java:677)
            at java.lang.Thread.run(Thread.java:479)


            As well, I took out the exception so that it was consistently attempting the roll-back.

            Still though, I can see the roll-back attempt but it doesn't seem to be rolling back at the database level.

            • 3. Re: Problem with rolling back transactions with JBoss 3.2.3
              cwoodill

              Here is the DB logs. I see an autocommit=1 and no transaction markers, so that is why it is not rolling back. Any idea why?

              040519 15:43:23 17 Connect eCity@kelly.radius.ad on eCity
               17 Init DB ecity
               17 Query select round('inf'), round('-inf'), round('nan')
               17 Query SHOW VARIABLES
               17 Query SET autocommit=1
               17 Query SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ
               17 Query Select * from test
               18 Connect eCity@kelly.radius.ad on eCity
               18 Init DB ecity
               18 Query select round('inf'), round('-inf'), round('nan')
               18 Query SHOW VARIABLES
               18 Query SET autocommit=1
               18 Query SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ
               19 Connect eCity@kelly.radius.ad on eCity
               19 Init DB ecity
               19 Query select round('inf'), round('-inf'), round('nan')
               19 Query SHOW VARIABLES
               19 Query SET autocommit=1
               19 Query SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ
               19 Query insert into test values ('test1')
               19 Query insert into test2 values ('test2')


              • 4. Re: Problem with rolling back transactions with JBoss 3.2.3

                That is because you are still allocating the connection in ejbCreate()

                If you really want to do this (I don't recommend it) you need to:

                1) Change deploy/transaction-service.xml to have SpecComplaint=true

                2) Define a resource-ref for your ejb that has something like the
                following example taken from the testsuite (NOTE the Unshareable):

                ejb-jar.xml

                ...
                 <session>
                
                 <ejb-name>UnshareableStateful</ejb-name>
                
                 <local-home>org.jboss.test.jca.interfaces.UnshareableConnectionStatefulLocalHome</local-home>
                
                 <local>org.jboss.test.jca.interfaces.UnshareableConnectionStatefulLocal</local>
                
                 <ejb-class>org.jboss.test.jca.ejb.UnshareableConnectionStatefulBean</ejb-class>
                
                 <session-type>Stateful</session-type>
                
                 <transaction-type>Bean</transaction-type>
                 <resource-ref>
                 <res-ref-name>jdbc/DataSource</res-ref-name>
                 <res-type>javax.sql.DataSource</res-type>
                 <res-auth>Container</res-auth>
                 <res-sharing-scope>Unshareable</res-sharing-scope>
                 </resource-ref>
                
                 </session>
                ...
                


                jboss.xml

                ...
                 <session>
                 <ejb-name>UnshareableStateful</ejb-name>
                 <resource-ref>
                 <res-ref-name>jdbc/DataSource</res-ref-name>
                 <jndi-name>java:/MySQLDS</jndi-name>
                 </resource-ref>
                 </session>
                ...
                


                • 5. Re: Problem with rolling back transactions with JBoss 3.2.3
                  cwoodill

                  Changed the code to have the connection within the user transaction it now works. Thanks JBoss Support!