Hi, working on a struts-web application using hibernate persistence tool. Since we using tomcat, my colleague suggest that we should avoid JTATransaction management and use default JDBCTransaction. We both a re new to hibernate and not sure where to demarcate out code with transactions. I have DAOs and service classes, then action classes. We plan to use the Hibernate session-per-request pattern with threadLocal configured with a context (can't say i understand much of that) i.e this ..
is configured within hibernate config file. My question is where exactly should the code session.beginTransaction() go? Here's my service class
Create a filter for your struts servlet and start it before and after the struts servlet is inovked. That's the easiest way. It's known as the 'open session in view' pattern, and will work so long as your web and ejb tier are on the save layer.
Whatever you do, do NOT do it in your DAOs. That's a rookie mistake.
Joined: Nov 27, 2008
Cameron Wallace McKenzie wrote:Create a filter for your struts servlet and start it before and after the struts servlet is inovked. That's the easiest way. It's known as the 'open session in view' pattern, and will work so long as your web and ejb tier are on the save layer.
We could have chosen the following alternative syntax - but we would never choose to do so with Tomcat:
Session session = HibernateUtil.getSessionFactory().getCurrentSession();
Why would we never use this alternative syntax with Tomcat? The difference between openSession() and getCurrentSession() is that the former, each time it is used, provides a brand new Hibernate Session. That is exactly what we want in our servlet. In contrast, getCurrentSession attempts to associate a Hibernate Session with a specific thread (the Singleton-per-Thread pattern), which Hibernate achieves via the use of an embedded (hidden) ThreadLocal. Unfortunately, Tomcat maintains a thread pool, and re-uses a given thread after a particular Http request is finished with it. Hence a brand new Http request can receive a previously used thread, which already happens to have a Hibernate Session associated with it (via the ThreadLocal), and getCurrentSession() may by chance receive an unrelated Hibernate Session when it ought to receive a brand new one. We may have a new Http session, and logically a new thread, but physically be re-using an existing thread. In this way, Tomcat 5.5.x and Hibernate 3.1 can confuse each other.
We choose to bypass the issue entirely by using SessionFactory.openSession, and avoiding the use of SessionFactory.getCurrentSession in a Tomcat environment.
The conflict we described above is readily testable. Setup a Tomcat 5.5 environment allowing only a small number of concurrent threads - say 3 or 4. (You accomplish this via an entry in Tomcat Root\conf\server.xml, namely by setting the maxThreads attribute of the applicable <Connector> element in this file to 3 or 4.) Create a couple of distinct, simplistic business transactions (conversational transactions or long-running transactions) which span Http requests. Attempt to preserve information in a ThreadLocal - any information �'�it doesn�'�t need to have anything to do with Hibernate - and do some tracing/logging in which you display the thread ID. You will see Tomcat thread pooling eventually recycle thread IDs to another business transaction, allowing inappropriate access to the ThreadLocal contents to take place.
Isn't Filter's or Interceptor Servlets exists to help achieve lazy loading?