9 Replies Latest reply on Dec 28, 2001 9:42 PM by lvyu

    Transaction Problems

    Dan Ciarniello Newbie

      I am having troubles using any transactional attributes other than 'NotSupported' in JBoss.

      While doing some rollback testing I noticed that while my first test run would work ok, the second test run would leave rows locked in the DB (SQLServer, in this case).

      The beans that I've developed look something like:

      public class EJB1 implements EntityBean
      {
      ...
      public void ejbRemove()
      {
      try
      {
      this.removeRow();
      }
      catch(SQLException se)
      {
      this.context.setRollBackOnly();
      throw new RemoveException(se.getMessage());
      }
      catch(Exception e)
      {
      throw new EJBException(e.getMessage());
      }
      }

      private void removeRow() throws SQLException
      {
      String sql = "delete from table1 where id = ?";
      PreparedStatement stmt = this.dbconn.prepareStatement(sql);
      stmt.setString(this.m_Id);
      stmt.executeUpdate();
      stmt.close();
      throw new SQLException("Rollback Test");
      }
      }

      The last line is simply to test that rollback works properly on error.

      My test client looks like:

      public class TestClient
      {
      public TestClient()
      {
      ... get Home interface ...
      home.remove(id);
      }

      public static void main(String args[])
      {
      TestClient test = new TestClient();
      }
      }

      In ejb-jar.xml I have set the transactional attribute to 'Required'.

      As stated above. The first run through TestClient works but the second does not.

      Using the SQLServer profiler I noticed that on the first run through, a rollback is sent to the DB but not on the second run. This, obviously, is the reason for the row-lock. The transaction has not been rolled back (i.e. its not finished).

      I started poking around in the JBoss code and discovered that when org.jboss.tm.TxCapsule.rollbackResources() is called, resourceCount is 1 the first time and 0 on subsequent calls. This explains why the rollback is not being sent. I also discovered org.jboss.tm.TxCapsule.addResource() is only called on the first run and not on the second. I think that explains why resourceCount is 0 on the second run. What I don't know is why addResource() is not called on the second run.

      I don't know whether the problem is my implementation/configuration or whether JBoss is the problem. Hopefully someone can shed some light on this problem.

      Any help is greatly appreciated.

      Thanks in advance,
      Dan Ciarniello

        • 1. Re: Transaction Problems
          David Jencks Master

          There's a limitation at the moment with bmp. You have to get your connection within each transaction context. Otherwise, as you discovered, after your first transaction on a connection completes, nothing else gets associated with a transaction. Aside from using cmp, here's what you have to do:

          (I think its ok to keep the DataSource reference although you probably want to null it in passivate and re-lookup in activate)

          Within each db-accessing method (such as your removeRow() method), get the connection you will use from the DataSource.

          Connection c = ds.getConnection();
          PreparedStatement s = c.prepareStatement(sql);
          ...
          ...

          When you get a connection within a transaction context, it will be enlisted in the transaction.


          I'm considering how to remove this limitation for jboss 3/rabbithole.

          • 2. Re: Transaction Problems
            Dan Ciarniello Newbie

            Thanks, David.

            That looks like it did the trick.

            Dan Ciarniello

            • 3. Re: Transaction Problems
              the DUG Newbie

              Do you have to keep the reference to the datasource?

              If so that means that everytime you passivate and null the reference then you will lose your next transaction?

              ALso, I am having trouble understanding where the 2nd invocation happens in this example..

              d.

              • 4. Re: Transaction Problems
                David Jencks Master

                You don't have to cache the datasource, you are free to look it up each time you need it. If you do cache it and set it to null on passivation you could always check if it was null and look it up before you try to use it.

                The multiple invocations were caused by his caching the connection between method calls.

                • 5. Re: Transaction Problems
                  Dan Ciarniello Newbie

                  The 2nd invocation happens when I re-run TestClient.

                  Also, I cache the datasource on setEntityContext() and null the reference on unsetEntityContext(). I don't null the reference on passivate so I don't lose the datasource and it is available on re-activation.

                  I'm not certain of the pros and cons of this approach but it is the approach that I've seen in various examples except that the examples cache the connection rather than the datasource.

                  Dan Ciarniello.

                  • 6. Re: Transaction Problems
                    zx44093 Newbie

                    Hi David,

                    I am new to EJB tansaction. Just wondering when using BMP and get a connection from data source pool, are we going to get the same connection within the same transaction of a session bean method call? Or, we have to pass down the connection to each JDBC call of the entity bean? I am declaring the transaction-type as required in both session bean and entity beans.

                    Thanks a lot if anyone can help my understand this clearly.




                    >>
                    There's a limitation at the moment with bmp. You have to get your connection within each transaction context. Otherwise, as you discovered, after your first transaction on a connection completes, nothing else gets associated with a transaction. Aside from using cmp, here's what you have to do:

                    (I think its ok to keep the DataSource reference although you probably want to null it in passivate and re-lookup in activate)

                    Within each db-accessing method (such as your removeRow() method), get the connection you will use from the DataSource.

                    Connection c = ds.getConnection();
                    PreparedStatement s = c.prepareStatement(sql);
                    ...
                    ...

                    When you get a connection within a transaction context, it will be enlisted in the transaction.


                    I'm considering how to remove this limitation for jboss 3/rabbithole.

                    • 7. Re: Transaction Problems
                      David Jencks Master

                      The transaction manager/connection manager will make sure any connection you get is enrolled in the current transaction for your thread. With local transactions this will always be the same connection, for xa transactions it probably won't, but in that case it doesn't matter, the connection will still be in the correct transaction.

                      I don't think you can pass a connection in an ejb call -- it might work through a Local interface, but a Remote interface call has the possibility of having the parameters serialized, which is not possible for a Connection. I would certainly not recommend it, in any case. It breaks declarative transaction support: you will not be able to change to called method to RequiresNew or NotSupported and affect the passed in Connection.

                      • 8. Re: Transaction Problems
                        zx44093 Newbie

                        Thats David for explaining this.

                        • 9. Re: Transaction Problems
                          lvyu Newbie

                          Thanks David for the help