-->
These old forums are deprecated now and set to read-only. We are waiting for you on our new forums!
More modern, Discourse-based and with GitHub/Google/Twitter authentication built-in.

All times are UTC - 5 hours [ DST ]



Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 2 posts ] 
Author Message
 Post subject: Hibernate with CommandPattern in a JTA environment
PostPosted: Wed Aug 02, 2006 3:49 pm 
Expert
Expert

Joined: Sat Jan 17, 2004 2:57 pm
Posts: 329
Location: In the basement in my underwear
We went to a CommandPattern with Hibernate over a year ago (2 years?)and it has been working really well for us, especially in a non-jta environment. Essentially, we wanted to be able to enforce units of work to be bound to a single session/transaction w/o having to pass the session around between commands.

The basic gist of this is that when a Command that require db access is first executed it will look for the current session and start a transaction if necessary, execute the rest of the work, which may include other commands and then close off the transaction by either committing or rolling it back.

Initially, we had rolled our own ThreadLocal implementation to keep track of the session and then with the use of a counter determined when we were back to our 'root' command to perform the commit/rollback.

As the Hibernate team rolled out the currentSession() implementation from the SessionFactory we watched in anticipation that we could refactor our code to use the built in mechanism rather than maintaining our own.

Now, I am getting slightly different behaviour between a JTA and Non-JTA environment and want to do a sanity check to see if I am missing something. What initially led me down this questioning route was JBoss reporting that it was cleaning up Connections for me.

The following code is executed via a CommandHandler which is either just a Pojo (non-jta) or a StatelessSessionBean with a "Required" Transaction description (jta).


Code:
    public final void execute() throws CommandException {
        //wrap the database work in a transaction
        Session session = null;

        try {
            session = HibernateConfigurationHelper.getSessionFactory().getCurrentSession();
            Transaction tx = session.getTransaction();
            if (tx == null || !tx.isActive()) {
               session.beginTransaction();
               handlingTransaction = true;
           }
        } catch (Exception e) {
            throw new CommandException(e);
        }

        try {
            doWork();
            Transaction tx = session.getTransaction();
            if (tx != null && tx.isActive() && handlingTransaction) {
                tx.commit();
            }       
        } catch (CommandException ce) {
            if (handlingTransaction) {
            Transaction tx = session.getTransaction();
               if (tx != null && tx.isActive()) {
                  tx.rollback();
               }
            }
            throw ce;
        } catch (Exception e) {
            if (handlingTransaction) {
            Transaction tx = session.getTransaction();
               if (tx != null && tx.isActive()) {
                  tx.rollback();
               }
            }
            throw new CommandException(e);
        }
        finally {
            if (session != null) {
                if (handlingTransaction && session.isOpen()) {
                    System.out.println("############################# Session is open");
                }
            }
        }
    }


The doWork() can be anything including calling other commands but the handlingTransaction variable is used to indicate the root command. When the 'work' is done then it handles either committing or rolling back the transaction.

Now, in a non-JTA environment, by the time it gets to the finally block the session is closed. However, in a JTA environment the session is still open by the time it gets to the finally.

The pertinent properties from the 2 different configs are:

Non-JTA
Code:
        props.setProperty("hibernate.connection.release_mode", "auto");
        props.setProperty("hibernate.current_session_context_class", "thread");


JTA
Code:
        props.setProperty("hibernate.connection.release_mode", "auto");
        props.setProperty("hibernate.current_session_context_class", "jta");
        props.setProperty("hibernate.transaction.manager_lookup_class", "org.hibernate.transaction.JBossTransactionManagerLookup");
        props.setProperty("hibernate.transaction.factory_class", "org.hibernate.transaction.JTATransactionFactory");


I feel that I am missing something as the fact that the session is still open doesn't seem right to me. I had thought of simply checking to see if it was open and then close it but then thought against that as it might just be sweeping the problem under the carpet.

By the time our code is executing a transaction is already in an Active state so the newTransaction never gets set and prevents the commit from closing and flushing the session (as far as I can tell).

This is from the begin() method in JTATransaction


Code:
      try {
         newTransaction = ut.getStatus() == Status.STATUS_NO_TRANSACTION;
         if (newTransaction) {
            ut.begin();
            log.debug("Began a new JTA transaction");
         }
      }


So I assume the container is starting the transaction as soon as the initial call is made and my begin() and commit() isn't really doing anything beneficial.

But my questions are:
-Does our calling of begin and commit throw anything off the rails? Should we be preventing these calls in a JTA environment?
-Should we be doing something with the session manually? I really don't want to handle it in the ejb as the ejb handles everything and not just Hibernate access.
-Is there some other property setting we should be using?
-Am I completely simple and should I go and find a McJob?


Top
 Profile  
 
 Post subject:
PostPosted: Tue Nov 21, 2006 3:40 pm 
Expert
Expert

Joined: Sat Jan 17, 2004 2:57 pm
Posts: 329
Location: In the basement in my underwear
Ok, finally got around to looking at this again.

In re-reading the Hibernate Reference's section on transactions I came across the following which seemed to describe our situation exactly.

Quote:
However, it is often desirable to keep your persistence layer portable between non-managed resource-local environments,
and systems that can rely on JTA but use BMT instead of CMT. In both cases you'd use programmatic
transaction demaracation. Hibernate offers a wrapper API called Transaction that translates into the native
transaction system of your deployment environment. This API is actually optional, but we strongly encourage
its use unless you are in a CMT session bean.


Ok, great I thought, I use the above code but rather than using CMT I use BMT and I can use my code as is. However, I seem to be hitting the wall with the following:

In the ThreadLocalSessionContext the currentSession call simply creates or obtains a session and returns it. I can then start my transaction do the work and then commit or rollback.

However with the JTATransactionSessionContext it expects that the transaction is already started and will blow an exception otherwise which is actually slightly different from the ThreadLocalSessionContext behaviour.

Is there any way around this? i.e. I really don't want to have 2 places controlling my transaction code since the first quoted paragraph states that if you want your code to be portable between JTA and non-jta use BMT. If I have to have special handling for BMT vs my non-jta then it's not really that portable.

Am I missing something here?


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 2 posts ] 

All times are UTC - 5 hours [ DST ]


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
© Copyright 2014, Red Hat Inc. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc.