8 Replies Latest reply on Apr 16, 2009 4:22 AM by jms_j

    JTA Transaction multiplexing

    jms_j

      Hi,

      I currently have a need to have multiple database connections ( to the same database instance ) to participate in a single transaction. From what I have gathered, I actually need JTA transaction mutiplexing:

      1) See the subection "Multiplexing" in this link:
      http://publib.boulder.ibm.com/iseries/v5r2/ic2924/index.htm?info/rzaha/distrans.htm

      2) Followed by an example code:
      http://publib.boulder.ibm.com/iseries/v5r2/ic2924/index.htm?info/rzaha/JTAMultiConn.htm

      Backpedal a bit: I have a list of objects that I need to perform operations on. Currently, code is sequentially iterating through the list and perform the operation one at a time. I would like to run the operations concurrently, since each one is really indepedent of the other. However, all of them MUST participate in a single transaction.

      It is somewhat like this:
      A) Debit money from a single entity
      B) Credit money to N entities, where N could be anywhere from 1 to tens of thousands.

      All of this on a single database instance.

      At the moment, the crediting of the money is done sequentially, but I would like to do them concurrently, as each receiving entity is really independent of the other receiving entities. However, all of these must be done in a single transaction.

      Options:
      O1) Can't create threads, as this will be done inside a J2EE container.
      O2) Process the receiving entities concurrently via a JMS queue/ via a message-driven bean ( MDB ). .. but each receiver on that queue must "know" the transaction that is must join with / to. If all entities received the money without problem, then a commit can be made. This commit will therefore need to be made by the code that sent all the messages / entities into the JMS queue. Thus, each MDB, do not really commit, but could rollback if the money could not be credited to a single entity.

      Even though it is all done on a single database instance, I will still need XA capability as transaction multiplexing can only be done via XA.

      So using the sample code from IBM, I was trying to write some test code that will:

      T1) Create 2 XA connections from the same XA datasource, and have the 2 connections "join" a single transaction ... all on a single thread / JVM.

      T2) If above works, then write some MDB code that will obtain an XA connection from an XA datasource, "join" the connection to a pre-determined transaction Xid. The Xid would have been created by the code that sent the messages into the JMS queue, and it is that code ( the one that sent the messages into the JMS queue ) that will commit the transaction.

      However, I am having trouble modifying the code to work with JBoss:

      P1) All datasources and connections obtained via JNDI from JBoss are all "wrapper" ( e.g. WrappedDataSource, WrappedConnection, etc.. ). Thus, the corresponding XA methods are not available. For example, I could not call DataSourc e.getXAConnection(), or XAConnection.getXAResource() because of the wrapping.

      P2) How do I obtain an Xid with JBoss ? ... so that I can pass the Xid as part of the message into a JMS queue ?

      Last but not the least, even though there are 3 nodes in our JBoss cluster, I don't need a clustered post-office for this queue. In fact, I don't want a clustered post-office for this queue ONLY, to remove potential issues with a "clustered" transaction manager ( since I am passing the Xid into the JMS queue ). I know that a non-clustered post-office is possible, so that is really not an issue.

      Any help appreciated.

        • 1. Re: JTA Transaction multiplexing
          jhalliday

           

          "jms_j" wrote:
          I have a list of objects that I need to perform operations on. Currently, code is sequentially iterating through the list and perform the operation one at a time. I would like to run the operations concurrently, since each one is really independent of the other. However, all of them MUST participate in a single transaction.

          It is somewhat like this:
          A) Debit money from a single entity
          B) Credit money to N entities, where N could be anywhere from 1 to tens of thousands.

          All of this on a single database instance.

          *cough*database stored procedure*cough*
          I'm not to clear on why you want to do this in parallel? I'm guessing maybe there is some computationally expensive step that's missing from the description above? Because if not, you are not CPU bound anyhow, it's all down to the disk I/O in the db and paralleling the code won't give you much benefit.

          "jms_j" wrote:

          O1) Can't create threads, as this will be done inside a J2EE container.

          You can create threads in JEE, just not direct from business logic code in some parts of the container. See for example the JCA Work Manager.
          "jms_j" wrote:

          O2) Process the receiving entities concurrently via a JMS queue/ via a message-driven bean ( MDB ). .. but each receiver on that queue must "know" the transaction that is must join with / to.

          Yuck. With potentially tens of thousands of operations, that's tens of thousands of messages/threads, unless you batch operations into messages and even then it's still ugly. However if you really want to go down that route, serialize the tx content into the message and resume it in the message processing code. It's probably not pure JEE though, as end users normally should not mess with TransactionManager directly in that way.

          "jms_j" wrote:

          T1) Create 2 XA connections from the same XA datasource, and have the 2 connections "join" a single transaction ... all on a single thread / JVM.

          Assuming your db supports lock sharing between transaction branches, otherwise the connections wind up deadlocked. You did check concurrent access to shared data over the connections, right?

          "jms_j" wrote:

          P1) All datasources and connections obtained via JNDI from JBoss are all "wrapper" ( e.g. WrappedDataSource, WrappedConnection, etc.. ). Thus, the corresponding XA methods are not available. For example, I could not call DataSourc e.getXAConnection(), or XAConnection.getXAResource() because of the wrapping.

          Yup. It's the container's job to do connection management and resource enlistment on datasource you ask it to manage. If you want to do it your self you need to manually create and manage the XADataSource, not ask the container to do it for you.

          "jms_j" wrote:

          P2) How do I obtain an Xid with JBoss ? ... so that I can pass the Xid as part of the message into a JMS queue ?

          You don't. The Xid is non of your business, it's a matter for the transaction manager and the JCA to worry about. You can pass transaction context around if you really need to move a tx between threads but even that is not normally a matter for end users.

          • 2. Re: JTA Transaction multiplexing
            jms_j

             

            "jhalliday" wrote:
            "jms_j" wrote:
            I have a list of objects that I need to perform operations on. Currently, code is sequentially iterating through the list and perform the operation one at a time. I would like to run the operations concurrently, since each one is really independent of the other. However, all of them MUST participate in a single transaction.

            It is somewhat like this:
            A) Debit money from a single entity
            B) Credit money to N entities, where N could be anywhere from 1 to tens of thousands.

            All of this on a single database instance.

            *cough*database stored procedure*cough*
            I'm not to clear on why you want to do this in parallel? I'm guessing maybe there is some computationally expensive step that's missing from the description above? Because if not, you are not CPU bound anyhow, it's all down to the disk I/O in the db and paralleling the code won't give you much benefit.


            Yes ... there are computationally expensive business logic steps that I did not describe ... e.g. Insurance logic, are you receiving insurance, how much tax credit, is it a continuing cover, etc.. and various legal requirements set by the federal government before and after crediting the money to the receiving entity. So no, database stored procedure won't cut it, as all the business logic is in the the middle tier.


            "jhalliday" wrote:
            "jms_j" wrote:

            O1) Can't create threads, as this will be done inside a J2EE container.

            You can create threads in JEE, just not direct from business logic code in some parts of the container. See for example the JCA Work Manager.


            OK .. Thanks. will look into that ... But still, both java.sql.Connection and javax.transaction.Transaction are not thread-safe as far as I am aware. ( e.g. See setRollbackOnly() method Javadoc for javax.transaction.Transaction ... where it refers to the current thread ). Hence, the the need for transaction multiplexing.

            "jhalliday" wrote:
            "jms_j" wrote:

            O2) Process the receiving entities concurrently via a JMS queue/ via a message-driven bean ( MDB ). .. but each receiver on that queue must "know" the transaction that is must join with / to.

            Yuck. With potentially tens of thousands of operations, that's tens of thousands of messages/threads, unless you batch operations into messages and even then it's still ugly. However if you really want to go down that route, serialize the tx content into the message and resume it in the message processing code. It's probably not pure JEE though, as end users normally should not mess with TransactionManager directly in that way.


            Not sure where you get the idea that "end users are messing with TransactionManager" ?? ... unless of course, by end users, you mean developers that are using JTA ( like me ) instead of developers that are writing JTS implementations.

            "jhalliday" wrote:
            "jms_j" wrote:

            T1) Create 2 XA connections from the same XA datasource, and have the 2 connections "join" a single transaction ... all on a single thread / JVM.

            Assuming your db supports lock sharing between transaction branches, otherwise the connections wind up deadlocked. You did check concurrent access to shared data over the connections, right?


            Because each receiving entity is independent of another receiving entity ... they are locking only rows that are relevant for that entity only.

            "jhalliday" wrote:
            "jms_j" wrote:

            P1) All datasources and connections obtained via JNDI from JBoss are all "wrapper" ( e.g. WrappedDataSource, WrappedConnection, etc.. ). Thus, the corresponding XA methods are not available. For example, I could not call DataSourc e.getXAConnection(), or XAConnection.getXAResource() because of the wrapping.

            Yup. It's the container's job to do connection management and resource enlistment on datasource you ask it to manage. If you want to do it your self you need to manually create and manage the XADataSource, not ask the container to do it for you.


            So does that mean, I must not define the XADataSource in a oracle-xa-ds.xml ( It is an Oracle database ) file ?? What do you exactly mean by "create and manage the XADataSource" myself ?


            "jhalliday" wrote:
            "jms_j" wrote:

            P2) How do I obtain an Xid with JBoss ? ... so that I can pass the Xid as part of the message into a JMS queue ?

            You don't. The Xid is non of your business, it's a matter for the transaction manager and the JCA to worry about. You can pass transaction context around if you really need to move a tx between threads but even that is not normally a matter for end users.


            When you say "pass transaction context around", I presume you are referring to javax.transaction.Transaction ?

            I presume then, because I cannot obtain the Xid, that what is described in IBM websphere is not possible for JBoss ? How does a developer using JTA then call the methods in javax.transaction.Transaction that accept an XAResource .. Or for that matter, calling the methods in an XAResource that accept an Xid ?

            I presume that your response will be that this really all done by the TM / JTS, and should not really be of concern to end-developers ... but why were these methods in JTA if it is only to be used by JTS developers writing a JTS implementation instead of JTA end-developers?

            Thanks for the response.

            • 3. Re: JTA Transaction multiplexing
              jhalliday

               

              "jms_j" wrote:
              javax.transaction.Transaction ... not thread-safe as far as I am aware. ( e.g. See setRollbackOnly() method Javadoc for javax.transaction.Transaction

              The JTA spec does not require (or forbid) it, but some implementations support having a Transaction active on multiple Threads. The setRollbackOnly javadoc for Transaction does not mention Threads anywhere, nor would I expect it to. The corresponding method on UserTransaction, TransactionManager and TransactionSynchronizationRegistry does say that it effects the tx associated to the current thread, but I don't read that as implying the same tx can't be associated to other Threads concurrently.

              "jms_j" wrote:

              Not sure where you get the idea that "end users are messing with TransactionManager" ?

              You, or rather your code running in the JEE container, is an end user of the JTA API. As distinct from the container itself. The former should usually only use UserTransaction and Status, the remainder of the API being for the benefit of the container. The only time end user code is intended to use the full functionality of the API is when it's running in an unmanaged environment i.e. outside a container.

              The problems you are having seem to stem chiefly from the fact you are trying to find ways to do things the JEE designers never intended for you to do directly. The JEE model assumes the container will provide a nice user friendly way for you to access all the functionality you need, or simply does things on your behalf. Unfortunately in this instance that assumption is broken because JSR-237 died before doing anything useful.

              "jms_j" wrote:

              When you say "pass transaction context around", I presume you are referring to javax.transaction.Transaction ?

              Depends. If you are staying in the same container then yes. If the JMS is farming out parts of the job across remote consumers then you have more hoops to jump though as the Transaction object itself can't be shipped around in that way. Hence I distinguish the abstract concept of a transaction context from specific ways of representing or manipulating it.

              "jms_j" wrote:

              How does a developer using JTA then call the methods in javax.transaction.Transaction that accept an XAResource .. Or for that matter, calling the methods in an XAResource that accept an Xid ?

              Inside a JEE container, they typically don't. That's the container's job. See above. Of course if you really, really want to, then you look up the TransactionManager from JNDI and go wild. At that point you are stepping outside of what is considered strictly portable across JEE standard containers, since your 'paralling transaction work' code is conceptually an extension of the standard container functionality rather than just an app that uses it. If you can live with that limitation it's certainly possible.

              "jms_j" wrote:

              I presume that your response will be that this really all done by the TM and should not really be of concern to end-developers

              umm, good guess :-) Although I'd probably say 'JEE container' rather than TM, since some parts of the work really belong more in e.g. JCA territory rather than just JTA.

              "jms_j" wrote:

              ... but why were these methods in JTA if it is only to be used by .. developers writing a implementation instead of JTA end-developers?

              Because the JTA can also be used outside a JEE container, where the end user has to do all the work themselves.

              • 4. Re: JTA Transaction multiplexing
                jms_j

                 

                "jhalliday" wrote:
                "jms_j" wrote:
                javax.transaction.Transaction ... not thread-safe as far as I am aware. ( e.g. See setRollbackOnly() method Javadoc for javax.transaction.Transaction

                The JTA spec does not require (or forbid) it, but some implementations support having a Transaction active on multiple Threads. The setRollbackOnly javadoc for Transaction does not mention Threads anywhere, nor would I expect it to. The corresponding method on UserTransaction, TransactionManager and TransactionSynchronizationRegistry does say that it effects the tx associated to the current thread, but I don't read that as implying the same tx can't be associated to other Threads concurrently.


                Does JBoss' implementation support having a Transaction active on multiple threads within the same JVM / container ? I won't be farming out the messages to remote JMS consumers ... the post-office will be local only.

                Also, the setRollbackOnly() Javadoc does mention thread, as quoted below:

                Modify the transaction associated with the current thread such that the only possible outcome of the transaction is to roll back the transaction.


                "jhalliday" wrote:

                The problems you are having seem to stem chiefly from the fact you are trying to find ways to do things the JEE designers never intended for you to do directly. The JEE model assumes the container will provide a nice user friendly way for you to access all the functionality you need, or simply does things on your behalf. Unfortunately in this instance that assumption is broken because JSR-237 died before doing anything useful.


                Thanks for pointing that JSR. Even JSR 236 is inactive as well.


                "jhalliday" wrote:
                "jms_j" wrote:

                ... but why were these methods in JTA if it is only to be used by .. developers writing a implementation instead of JTA end-developers?

                Because the JTA can also be used outside a JEE container, where the end user has to do all the work themselves.


                I see. It seems that there is really no portable way to write code that will allow parallel work on the same transaction. I guess I'll have to weigh this possibility anyway.

                To give a bit of perspective, processing each receiving entity takes about 1.8 seconds, on average. Assuming there are 10,000 entities to be processed sequentially, that's 18,000 seconds, or about 5 hours when done sequentially... not to mention the various locks that are held on certain rows ... all because it needs to be in a single transaction.

                • 5. Re: JTA Transaction multiplexing
                  jms_j

                   

                  "jhalliday" wrote:
                  "jms_j" wrote:

                  P1) All datasources and connections obtained via JNDI from JBoss are all "wrapper" ( e.g. WrappedDataSource, WrappedConnection, etc.. ). Thus, the corresponding XA methods are not available. For example, I could not call DataSourc e.getXAConnection(), or XAConnection.getXAResource() because of the wrapping.

                  Yup. It's the container's job to do connection management and resource enlistment on datasource you ask it to manage. If you want to do it your self you need to manually create and manage the XADataSource, not ask the container to do it for you.


                  Hi Jonathan,

                  I saw this other post from you:

                  http://www.jboss.org/index.html?module=bb&op=viewtopic&p=4132880#4132880

                  ... about obtaining the XADataSource class instead of the WrapperDataSource. Can this be done even outside of JCA ( given the context of this thread / discussion ) ?


                  • 6. Re: JTA Transaction multiplexing
                    jhalliday

                    >Does JBoss' implementation support having a Transaction active on multiple threads

                    yes

                    > Also, the setRollbackOnly() Javadoc does mention thread

                    True for some occurances of the method. However, the version of that method on the Transaction API does not. it says 'Modify the transaction associated with the target object such that the only possible outcome of the transaction is to roll back the transaction.'

                    > ...about 5 hours when done sequentially ... all because it needs to be in a single transaction.

                    Sounds to me like your transaction design is broken. ACID transactions that span more than a few minutes are generally a Bad Thing. Perhaps consider extended transaction models instead.

                    > Can this be done even outside of JCA ( given the context of this thread / discussion ) ?

                    yes

                    • 7. Re: JTA Transaction multiplexing
                      jms_j

                       

                      "jhalliday" wrote:

                      > Can this be done even outside of JCA ( given the context of this thread / discussion ) ?

                      yes


                      OK ... rereading the thread that I mentioned ( http://www.jboss.org/index.html?module=bb&op=viewtopic&p=4132880#4132880 ), that discussion actually ended up with only obtaining the classname of the XADataSource implementation, not obtaining an actual instance of an XADataSource.

                      I presume that's what you ended up doing ? Obtain the classname, create an instance of it and setting the properties, then obtain a connection from it ?



                      • 8. Re: JTA Transaction multiplexing
                        jms_j

                         

                        "jhalliday" wrote:
                        >Does JBoss' implementation support having a Transaction active on multiple threads

                        yes



                        I should ask: How does JBoss deal with statement execution and resultsets that are running through the same transaction from different threads ?