12 Replies Latest reply on May 25, 2003 7:54 AM by Adrian Brock

    Question/Problem with local transactions

    Frank Griffin Novice

      I'm getting a message I don't understand in the context of what I'm trying to do. The message was cryptic in the 3.0.x series ("Prepare called on local tx; you are not getting the sematics you think !"), so I switched to 3.2.1 in the hope of a better one, and got it. Here it is:

      17:21:16,398 WARN [TxConnectionManager$LocalXAResource] Prepare called on a local tx. Use of local transactions on a jta transaction with more than one branch
      may result in inconsistent data in some cases of failure.

      The trouble is, I have no idea what this means.

      Here's what I'm doing:

      I have client C calling stateless session EJB S which is a facade for entity EJB E. This call creates an entity instance, populates it, and then sends a JMS message including the entity instance key to a queue attached to message-driven EJB M. M then creates an instance of S, and calls methods of S which locate the entity instance by the passed key, and access (and modify) the instance data.

      Both S and M (as well as E) are described in the ejb-jar as trans-attribute Required, so my expectation was that they would lock each other out.

      Instead, I get this message, and the S methods invoked by M are not seeing changes that were made during the client call (more accurately, they are finding the entity EJB instance under the created key, but not seeing the data that was set into the instance by the methods of S during the call from client C).

      My primary tutorial on all this has been Monson-Haefel's book, which mentions nothing about "local transactions". Moreover, I am not doing any explicit transaction control (this is all Container-managed), so I'm not calling Prepare at all.

      Could somebody please translate this message for me ? Am I doing something wrong in the above scenario, or is this an internal error (I rather suspect my design) ? If the former, can you tell me what ?

        • 1. Re: Question/Problem with local transactions
          Frank Griffin Novice

          I should be more specific about what I was expecting here.

          I was expecting, even though the MDB triggered by the message sent from the client-created session EJB might create a competing session EJB instance method call (i.e. one which would execute before the client-created session EJB method call had finished), that the fact that they were operating under separate transactions would cause the MDB-created session EJB method call to block until the client-created session EJB method call had completed its transaction, and the back-end datastore changes had been committed. The result I expected was that the MDB-created session EJB method calls would "see" the changes made by the client-created session EJB method calls.

          The only pertinent grey area I can find in the Monson-Haefel book is the subject of "isolation". The book states that support of the various isolation levels is vendor-specific, but I could find nothing in the JBoss QuickStart that mentioned anything about JBoss-specific deployment files which controlled isolation levels.

          Obviously, I'm looking for an isolation level which blocks reads of resources modified within transactions until those transactions have completed.

          I can provide anything from the binary EAR to the source code to help resolve this problem.

          • 2. Re: Question/Problem with local transactions
            Frank Griffin Novice

            I tried inserting a Thread.sleep(10000) in the MDB's onMessage() method, thinking that if the MDB and the client-session transactions were really just overlapping, then that ought to allow the entity EJB to be written back to the datastore before the MDB proceeded to read it. Same result.

            It really looks as though the MDB is running as some strange sort of synchronous extension of the client-session transaction that sends the message, and I can't figure out why. Everything I've read says that the MDB should be an independent unit of work and that it should block on the entity instance until the client-session transaction is done with it. Given the 10-second wait, the first transaction ought to be ancient history by the time the MDB tries to read the entity, but apparently it's not.

            Can anybody offer some advice here ?

            • 3. Re: Question/Problem with local transactions
              Frank Griffin Novice

              I tried inserting a Thread.sleep(10000) in the MDB's onMessage() method, thinking that if the MDB and the client-session transactions were really just overlapping, then that ought to allow the entity EJB to be written back to the datastore before the MDB proceeded to read it. Same result.

              It really looks as though the MDB is running as some strange sort of synchronous extension of the client-session transaction that sends the message, and I can't figure out why. Everything I've read says that the MDB should be an independent unit of work and that it should block on the entity instance until the client-session transaction is done with it. Given the 10-second wait, the first transaction ought to be ancient history by the time the MDB tries to read the entity, but apparently it's not.

              Can anybody offer some advice here ?

              • 4. Re: Question/Problem with local transactions
                Frank Griffin Novice

                I tried inserting a Thread.sleep(10000) in the MDB's onMessage() method, thinking that if the MDB and the client-session transactions were really just overlapping, then that ought to allow the entity EJB to be written back to the datastore before the MDB proceeded to read it. Same result.

                It really looks as though the MDB is running as some strange sort of synchronous extension of the client-session transaction that sends the message, and I can't figure out why. Everything I've read says that the MDB should be an independent unit of work and that it should block on the entity instance until the client-session transaction is done with it. Given the 10-second wait, the first transaction ought to be ancient history by the time the MDB tries to read the entity, but apparently it's not.

                Can anybody offer some advice here ?

                • 5. Re: Question/Problem with local transactions
                  Frank Griffin Novice

                  In reading the 2.0 spec, I'm now getting the impression that the transaction context of the sender of the message can be propagated to the MDB which processes the message. I tried changing the trans-attribute of the MDB to "NotSupported", but got the same result.

                  How do I force the MDB's processing to be completely divorced from the processing of the transaction that sends the JMS message ?

                  • 6. Re: Question/Problem with local transactions
                    Adrian Brock Master

                    The answer to your first question
                    is that you are using a local resource
                    in a transaction with an XAResource.

                    The local resource has no perpare so you
                    get a warning that its commit might fail.

                    The second question depends upon how you
                    are accessing the data. If you use
                    default CMP you will get serialized access.

                    I guess you are using direct jdbc with something
                    hsql which has no transaction isolaton support.

                    Regards,
                    Adrian

                    • 7. Re: Question/Problem with local transactions
                      Frank Griffin Novice

                      OK, I *think* I see the problem...

                      I dropped an exception into TxConnectionManager at the point of the warning, and the resulting stacktrace showed that the Prepare call was made during endTransaction and none of my code was in the trace. Ergo, it had to be something in the ejb-jar.xml.

                      When I looked, I found that the S session EJB had a ejb-local-ref to itself, because the S methods call methods in other classes which need to call S methods themselves, so they were going to JNDI, getting a home, then getting an S handle, and calling the method.

                      I thought that trans-attribute "Required" meant that if a transaction was already in-flight, the S EJB would execute as part of that transaction. But it seems that getting a second S instance is causing some sort of transaction fork, rather than having the calls to the S methods under the second S instance just run as part of the transaction started by the client's call to the first instance.

                      I'll change the design to promulgate the session bean handles rather than have the other classes create their own. But, should this have worked ? Is it a server bug, or user error ?

                      • 8. Re: Question/Problem with local transactions
                        Frank Griffin Novice

                        I'm sorry, I'm still not getting this. According to what I've read, getting a Local EJB reference from a LocalHome is the way classes are supposed to call methods on session beans, and S can't pass "this" to other classes to enable them to invoke S's methods.

                        So the situation is ((r)=remote, (l)=local):
                        1) Client calls (r)S.method1() via Remote interface
                        2) (r)S.method1() creates local instance of E and populates its fields
                        3) (r)S.method1() calls Utility.method2() which goes to JNDI, gets a LocalHome object for S, and from it gets a local reference to S, (l)S
                        4) Utility.method2() calls (l)S.method3(), passing the primary key of the E instance created above
                        5) (l)S.method3() goes to JNDI, gets a LocalHome for E, and does a findByPrimaryKey() to get that instance of E, and gets/sets some fields
                        6) Everybody returns, and (r)S.method1() sends a JMS message to the M MDB EJB containing the entity EJB E's primary key; it then returns, ending the transaction.
                        7) TxConnectionManager makes its complaint.
                        8) M.onMessage() gets control, goes to JNDI, gets a LocalHome for S, gets a local reference to S, and calls (l)S.method4() passing the primary key of the E instance created above.
                        9) (l)S.method4() does a findByPrimaryKey() to get that instance of E, and does NOT find the changes that were supposed to be committed in (6)-(7).

                        What am I doing wrong here ? What is the "local" versus "XA" distinction ? How else would Utility.method2() call S.method3() ?
                        I'm very confused....

                        • 9. Re: Question/Problem with local transactions
                          Frank Griffin Novice

                          No, no, ignore me (for now, anyway). I've found that it is only certain of the changes that aren't showing up; most of them are there, so it's got to be an application error somewhere.

                          I'd still like to know what JBoss is complaining about and if I'm doing what I'm doing in a flawed way, but it seems almost certain that the warning is not interfering with committing the changes.

                          • 10. Re: Question/Problem with local transactions
                            Adrian Brock Master

                            Your entity bean is using a local transaction.
                            It has no XA behaviour.

                            JMS uses an XAResource.

                            transaction.commit();
                            jmsXAResource.prepare(); // OK
                            localResource.prepare(); // Warning
                            jmsXAResource().commit; // guaranteed to work it localResource.commit(); // might fail (no preparation)
                            was prepared ok

                            The problem is that your database does not
                            support XA.

                            Regards,
                            Adrian

                            • 11. Re: Question/Problem with local transactions
                              Frank Griffin Novice


                              > The problem is that your database does not
                              > support XA.

                              That's what I don't understand. I'm not using a database at all. The only persistent data here is the entity bean which is being stored wherever JBoss chooses to store it (Hypersonic ?).

                              Is a "local transaction" one initiated when a client calls an EJB through its Local Interface rather than the Remote Interface ? Why would this make a difference ?

                              What's confusing me is that all of my contributions to the transaction handling are being done through the ejb-jar.xml, i.e. they are JBoss-neutral. The code itself has no explicit transaction handling, and no resources other than those chosen and controlled by JBoss (e.g. the container persistent storage, JMS queues) are involved.

                              If what I'm doing is correct according to spec, then I shouldn't be getting the warning. If what I'm doing is not correct, then I should be able to correct it and the warning should go away. However, in the second case I need to know what it is I'm doing that is not correct.

                              Is there any way to find out what non-XA resource is the focus of the warning ?

                              • 12. Re: Question/Problem with local transactions
                                Adrian Brock Master

                                Hypersonic has has no XA adaptor.

                                So your CMP is the local transaction.

                                Regards,
                                Adrian