4 Replies Latest reply on Aug 4, 2008 12:10 PM by Peter Johnson

    Calling datasource.getConnection() after sessionContext.setR

    Alexey Fedotov Newbie

      Hello.
      I am adapting an old application which worked on JBOSS 2.1 to the new JBOSS server version.
      Now I am using JBOSS 5.0.0.Beta4.

      There is a code in the application which acts like the following (simplified):

      javax.ejb.SessionContext sessionContext = ...;
      ...
      if (somethingGoesWrong()) {
       sessionContext.setRollbackOnly();
      
       //Then get connection to the DB
       javax.sql.DataSource dataSource = ....;
       java.sql.Connection con = dataSource.getConnection();
      
       //and execute a query
       ...
      }
      



      The following exception is thrown when "dataSource.getConnection()" executes:
      org.jboss.util.NestedSQLException: Transaction is not active:
      tx=TransactionImple < ac, BasicAction: -3f57fffe:745:48918030:537 status: ActionStatus.ABORT_ONLY >;
      - nested throwable: (javax.resource.ResourceException: Transaction is not active:
      tx=TransactionImple < ac, BasicAction: -3f57fffe:745:48918030:537 status: ActionStatus.ABORT_ONLY >)
       at org.jboss.resource.adapter.jdbc.WrapperDataSource.getConnection(WrapperDataSource.java:94)
      


      Is it a JBOSS bug or such code really should not work?



      I tried to debug using JBOSS sources. The exception is thrown from org.jboss.resource.connectionmanager.TxConnectionManager:
      public ConnectionListener getManagedConnection(Subject subject, ConnectionRequestInfo cri)
       throws ResourceException
       {
       Transaction trackByTransaction = null;
       try
       {
       Transaction tx = tm.getTransaction();
       if (tx != null && TxUtils.isActive(tx) == false)
       throw new ResourceException("Transaction is not active: tx=" + tx);
       ...
      

      So if transaction is not in Status.STATUS_ACTIVE (TxUtils.isActive(tx)) then throw an exception.
      Link to current source:
      http://viewvc.jboss.org/cgi-bin/viewvc.cgi/jbossas/trunk/connector/src/main/org/jboss/resource/connectionmanager/TxConnectionManager.java?revision=76091&view=markup


      Older version of this class used another check method:
      ...
      if (trackConnectionByTx && tm.getStatus() != Status.STATUS_NO_TRANSACTION)
       tx = tm.getTransaction();
      ...
      

      Link to older source:
      http://viewvc.jboss.org/cgi-bin/viewvc.cgi/jbossas/trunk/connector/src/main/org/jboss/resource/connectionmanager/TxConnectionManager.java?revision=30026&view=markup

      If transaction is not in Status.STATUS_NO_TRANSACTION then it is ok.

      Older version of TxUtils.isActive(Transaction tx) was also functioning in the different way.

      Old: TxUtils.isActive() returns true if the transaction is in Status.STATUS_ACTIVE or Status.STATUS_MARKED_ROLLBACK.

      Current: TxUtils.isActive() returns true if the transaction is in Status.STATUS_ACTIVE.

      All these changes were made corresponding to this issue: https://jira.jboss.org/jira/browse/JBAS-1916.

      TxUtils.isActive() - it is ok. But I can not understand why TxConnectionManager changed to the way it works now.

      If I did not read some documentation please direct me to it.



      Thanks for all people who will answer something or even read this to the end. :)

        • 1. Re: Calling datasource.getConnection() after sessionContext.
          Peter Johnson Master

          I know that this is not a solution, but I recommend first trying this in 4.2.2 or 4.2.3. There are many bugs in the 5.0 betas (and even in CR1), and trying 4.2.x would at least eliminate that possibility.

          If it still doesn't work in 4.2.x then we'll have to look at what your code is doing. And figuring out at what point the transaction became inactive.

          • 2. Re: Calling datasource.getConnection() after sessionContext.
            jaikiran pai Master

            As Peter said, its better to try it against 4.2.x first.

            Also,

            if (somethingGoesWrong()) {
             sessionContext.setRollbackOnly();
            
             //Then get connection to the DB
             javax.sql.DataSource dataSource = ....;
             java.sql.Connection con = dataSource.getConnection();
            
             //and execute a query
             ...
            }


            How about re-ordering the statements? The sessionContext.setRollbackOnly() is going to mark the transaction for rollback. So why not get the datasource connection and run the query first (probably through a @RequiresNew transaction method) and then setRollbackOnly on the sessionContext.


            • 3. Re: Calling datasource.getConnection() after sessionContext.
              Alexey Fedotov Newbie

              Peter, Jaikiran,
              thank you for you participation.

              I have just tested it on jboss-4.2.3.GA. It throws the same exception.

              Actually as it can be seen on "Fix Version/s" and "Subversion Commits" tab on https://jira.jboss.org/jira/browse/JBAS-1916 such behavior have been introduced in JBossAS-4.0.3RC1.

              I think it would be not good to use an older version.

              Jaikiran, i thought about changing order of statements. But there is a problem with it. The code which I presented here is a simplified concept. Real code is much more complicated. The application which i am adapting is quite a big one and I have already seen few different places in which it tries to get a connection after possible setRollbackonly(). And i am not sure about how many more such places there are.

              I understand that setRollbackOnly() marks transaction for rollback. But i think that it should not be prohibited to take a connection and make queries (reading) even after marking it for rollback because it is marked but not actually rolled back at that moment.

              As I can see for now I have 2 variants:
              1. Try to override TxConnectionManager to make it providing the behaviour i need. I think there should be a way to make an overriding child class and to provide it for JBOSS to use through the configuration files. Or may be i have to change and recompile JBOSS library sources...
              2. Try to find and reorganize all such places in my application.
              It will be very hard because of complicated and undocumented code.

              • 4. Re: Calling datasource.getConnection() after sessionContext.
                Peter Johnson Master

                You might consider posting this in the JBossTM forum, the experts there might have a better idea on what the issue is.