Announcement Announcement Module
Collapse
No announcement yet.
Transactions spanning database and server upload etc. Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Transactions spanning database and server upload etc.

    Hi,

    I am pretty much a beginner with Spring, and I am trying to set up a new architecture with Spring and Hibernate.

    We have one database, but also a server that our clients talk to. For example, they can upload a form to the server and access it later (it's details also get added to the database).

    I would like to combine these two actions - uploading the form to the server, and updating the database - into a single "transaction", but, I am having a particular problem figuring out how to configure Spring in such a case.

    For example, if the form is uploaded ok, but updating the database fails for some reason, how does Spring know how to roll back the uploading of the form to the server ie to call a method that removes it from the server? Do I need to define some kind of transaction manager for the server? If so, any pointers would be appreciated!

    cheers, and apologies if this isn't clear!

    David

  • #2
    Just to clarify - I'm trying to use the Declarative Transaction management. Thanks.

    Comment


    • #3
      The file system isn't transactional. So you would need to write code to delete the file if the DB transaction fails. Alternatively, you could consider writing the data to a BLOB in the DB in the same transaction, so that a single Spring tx can span both storing the information about the data and the data itself.

      Comment


      • #4
        Hi Rod,

        Actually our server is seperate, so uploading a form to the server is more than writing to the filesystem - we have to connect to the server, call it's API to upload it etc..

        What I'm trying to get my head around is whether I can write some code to allow Spring to "know what to do" if I need to rollback both the transaction that spans both the db transaction (Hibernate) and my own transaction with the server. eg is there any way to tell Spring to "include this when you rollback a transaction" in a declarative mode?

        Can I set up some kind of transaction manager for the server that Spring can recognize and use? If not, and I have to write it each method to handle a transaction rollback programmatically (soemthing I really want to avoid if possible), do I have to change how I handle Hibernate transactions to combine the two?

        Hope this is at least a little clear as what I'm trying to achieve!

        cheers,

        David

        Comment


        • #5
          Yes, you can attach to the transaction synchronization that Spring is already using. This is how thread bound resources such as Hibernate Session Factories get handled, for example.

          There's no real documentation on doing this, since this is normally used internally, however all the classes in question have pretty extensive JavaDocs, and there is lots of sample code in terms of the various pieces of code that use this mechanism (Hibernate integration, iBatis, JDO, etc.).

          Regards,

          Comment


          • #6
            Thanks for the suggestion.

            This is my first look at the Spring code - all the transaction stuff is a little overwhelming at first glance!!

            Would anyone be kind enough to give me a brief overview at the code level, and pointers on where I need to insert / extend things to do what I'm trying to do?

            Would really appreciate it...

            cheers,

            David

            Comment


            • #7
              TransactionSynchronizationManager is the basic for synchronization with the current transaction, via thread bound holders for resources.

              Take a look at how it is used for example via SessionFactoryUtils and HibernateInterceptor. SessionFactoryUtils.getSession ultimately ends up registering a new synchronization, where the Hibernate Session is kept in a SessionHolder class, which is registered (indirectly as a an SpringSessionSynchronization class) as a transaction synchronization. This basically gets callbacks to synchronize with events on the transaction. Looking at HibernateInterceptor, you can see how an interceptor can get in on the action. If you look at the invoke method, the call to getSession will cause the binding and synchronization to happen if there is none. The 'else' case handles the situation where the HibernateInterceptor is applied (accidentally) before the transaction interceptor itself, ensuring that the newly created session is at least still bound to the current thread, althoughin this case it will not be also synchronized to the transaction, since there is no synchronization registered in this case, as the tx doesn't even exist yet. However, that will happen later when a session is requested, as SessionFactoryUtils getSession() will notice that the session needs to be registered.

              Hope this helps,

              Regards,

              Comment


              • #8
                Just a note for anybody watching this topic that I revised the last 3-4 lines of my previous post. The current description is accurate.

                Comment


                • #9
                  Working my way slowly through all this...!

                  Another question emerges - for just the database stuff, I have a TransactionProxyFactoryBean set up for my Service Object (Manager), linked to a HibernateTransactionManager.

                  Now, to handle the database transactions and the server transactions, can I create a ServerTransactionManager and link the 2 together somehow? Or do I need to create a single HibernateAndServerTransactionManager and apply it to my Service object?

                  cheers,

                  David

                  Comment


                  • #10
                    You should almost never need more than one transaction manager.

                    Just transactionally wrap (using TransactionProxyFactoryBean or BeanNameAutoProxyCreator) all the service objects which need to be transactional. There is no issue if they call into each other, either.

                    Regards,

                    Comment


                    • #11
                      Hi Colin,

                      But that's the thing - I have a Service object called FormManager, which makes calls to the database using my FormDAO which uses HibernateTemplate, and in the same method (addForm()) also calls the server API using my FormsetDAO (on the Server it's called a FormSet) which will be managed by my Server transaction stuff.

                      So, what do I set as the Transaction manager for the FormManger service object when I wrap it as TransactionProxyFactoryBean? At the moment it's the HibernateTransactionManager, but that's without the server stuff...

                      Many thanks,

                      David

                      Comment


                      • #12
                        Presumably you are going to add your own code to synchronize to the existing database transactions (as per the previous entries), but that can still all be handled through the one transaction manager, HibernateTransactionManager in this case. The fact that this transaction manager is Hibernate aware and creates a session to bind to the current thread/tx on entry does not impede synchronizing other aspect to it as well...

                        Everything that needs to be transactional needs to be wrapped with a proxy which is hooked up to this transaction manager. When it comes to your server stuff which needs to synched in, you have to do it in a fashion similar to the way the existing classes which do this kind of thing (like SessionFactoryUtils) do it.

                        Regards,


                        Regards,

                        Comment


                        • #13
                          Colin,

                          thanks! That was one of the missing pieces!! Things are progressing much better now...

                          Just a quick qu:

                          Is there any reason that SpringSessionSynchronization (inner class in SessionFactoryUtils) receives both the SessionHolder and the SessionFactory - can't it just get the SessionHolder using the SessionFactory via TransactionSynchronizationManager?

                          cheers,

                          David

                          Comment


                          • #14
                            I too have a similar need. In our current system, we "simulate" XA txns via a composite TransactionManager (of our own design), in which Oracle, JMS, and other instances get registered. Since our TransactionManager is not really XA (it just does its best using single phase commit) the registered sub-managers are assigned a priority. For example, JMS is always the lowest priority so that messages are only sent to clients if all else succeeds. While this leaves some holes, it is very fast compared to XA.

                            So, my question: From your posts and my browsing, I gather that there is no concept of a composite TransactionManager in spring. And that TransactionSynchronizationManager is used to register resources that will be called back by AbstractPlatoformTransactionManager.

                            But we would like to use the predefined spring Hibernate and JMS txn managers (and get rid of our own). So I'm a bit confused as to how to proceed in recreating our "poor-mans" XA using spring.

                            Comment


                            • #15
                              Originally posted by hay7777
                              Just a quick qu:

                              Is there any reason that SpringSessionSynchronization (inner class in SessionFactoryUtils) receives both the SessionHolder and the SessionFactory - can't it just get the SessionHolder using the SessionFactory via TransactionSynchronizationManager?
                              David
                              Consider the resume method for example, where it needs to rebind the session holder with the session factory as the key. That's at least one place it needs both. Once it has it for that, it may as well use it in a number of other places directly (it's cleaner), even if it could theoretically get it from the synchronization manager.

                              Comment

                              Working...
                              X