-->
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.  [ 19 posts ]  Go to page 1, 2  Next
Author Message
 Post subject: Session handling antipattern? (ThreadLocal + disconnect)
PostPosted: Tue Jan 27, 2004 10:26 am 
Beginner
Beginner

Joined: Wed Dec 03, 2003 10:59 am
Posts: 47
Hello,

Just read Gavin's latest blog post about managing Hibernate Sessions:
http://blog.hibernate.org/cgi-bin/blosxom.cgi

I am now concerned that I may be using session-per-user-session antipattern.

I have a web application.
I have a ServiceLocator object.
In its static block I create ThreadLocal instance: ThreadLocal SESSIONS = new ThreadLocal();
In ServiceLocator constructor I get a static reference to Hibernate's SessionFactory object.

ServiceLocator has a method that I call from each DAO method, which may execute 1 or more transactions using the same Session, returned by this method.
This method is below (exception handling removed to make code shorter):

Code:
    public static Session currentSession()
    {
        Session ses = (Session) SESSION.get();
        if (ses == null)
        {
            LOG.debug("SESSION IS NULL, MAKING A NEW ONE");
            ses = _sesFactory.openSession();
            SESSION.set(ses);

            LOG.debug("Opened Hibernate Session");
        }
        else
        {
            LOG.debug("SESSION IS NOT NULL");
        }
        if (!ses.isConnected())
        {
            LOG.debug("SESSION IS NOT CONNECTED, re-CONNECTING");
            ses.reconnect();
        }
        return ses;
    }


Two more important things:

1. This is a web application. Each user request may result in several DAO methods being called sequentially and in the same thread. Each of this methods calls the above currentSession() method. This means that they will all get references to the same Session object that is stored in that ThreadLocal SESSION instance.
I think this is okay.
Is it?

2. At the end of the user request, in the Servlet Filter, the following method is called:
ServiceLocator.disconnectSession(), which calls disconnect() on the Hibernate Session object, like this:

Code:
    public static void disconnectSession()
    {
        Session ses = (Session) SESSION.get();

        if (ses != null)
        {
            try
            {
                if (ses.isConnected())
                {
                    LOG.debug("DISCONNECTING SESSION");
                    ses.disconnect();
                }
                else
                {
                    LOG.debug("SESSION ALREADY DISCONNECTED");
                }
            }
        }
    }

Is this the right thing to do?

Should I be calling Session's close() method and removing Session from ThreadLocal SESSION object: SESSION.set(null) ?

Thank you,
Otis


Top
 Profile  
 
 Post subject:
PostPosted: Tue Jan 27, 2004 10:54 am 
Hibernate Team
Hibernate Team

Joined: Tue Aug 26, 2003 12:50 pm
Posts: 5130
Location: Melbourne, Australia
This code is okay, but what is missing is that you should be closing the session at the end of each application transaction. As it stands, you have a memory leak, and a cache that gets more and more stale as time passes.


Top
 Profile  
 
 Post subject:
PostPosted: Tue Jan 27, 2004 10:56 am 
Hibernate Team
Hibernate Team

Joined: Tue Aug 26, 2003 12:50 pm
Posts: 5130
Location: Melbourne, Australia
Ummm. One more problem:

it doesn't look like the session is being allocated to a particular user! looks as if the session gets allocated to a pooled thread! That is terrible, if correct.


(Also I don't see where you flush the session.)


Top
 Profile  
 
 Post subject:
PostPosted: Tue Jan 27, 2004 11:36 am 
Beginner
Beginner

Joined: Wed Dec 03, 2003 10:59 am
Posts: 47
gavin wrote:
This code is okay, but what is missing is that you should be closing the session at the end of each application transaction. As it stands, you have a memory leak, and a cache that gets more and more stale as time passes.


I thought that I understood what you meant by "application transaction" and that in the realm of web applications that meant "a user request" (begin to end of servicing of a request).
Is this incorrect?

And when you say "you should be closing the session at the end of each AT", do you mean that I should be calling session.close() instead of session.disconnect() at the end of servicing the user request (which should equal an AT, if I understand you correctly)?


gavin wrote:
Ummm. One more problem:

it doesn't look like the session is being allocated to a particular user! looks as if the session gets allocated to a pooled thread! That is terrible, if correct.


Regarding user assignment - I am not assigning the Session to a user anywhere explicitly.
I thought using ThreadLocal would automatically provide that:

Code:
Serlvet has e.g. 10 threads

User A makes a request and gets Thread T1
  T1 has no Session associated with it, so I create a new Session and associate it with T1
User A completes request, so I call session.disconnect(), but leave Session associated w/ T1

User B makes a request and gets T1, which is now available
  T1 already has a Session associated with, but it is disconnected, so I call session.reconnect()
User B completes request, so I call session.disconnect(), but leave Session associated w/ T1


Is this wrong?
That is, can multiple users share the same Session instance if their access to it is sequential (in this example user B could not get Session in T1 thread before user A was done with T1 and before his session was disconnect()ed)

If this is wrong, then are you saying that all I need is something like:

Code:
private static Map userToSessionMap = new HashMap();


where keys are userIds, for example, and values are Hibernate Sessions.
And then just provide appropriate accessors to this to get and remove Sessions?

In that case, is ThreadLocal in the servlet environment a bad idea?



gavin wrote:
(Also I don't see where you flush the session.)


Regarding flushing the Session - some of my DAO methods call session.flush() explicitly, but most do not. Most are in transactions (beginTransaction + commit or rollback).

Do I need to add explicit, manual session.flush() calls every time I do update(), save(), saveOrUpdate()?


Thanks for such speedy help!
Otis


Top
 Profile  
 
 Post subject:
PostPosted: Wed Jan 28, 2004 10:13 am 
Beginner
Beginner

Joined: Wed Dec 03, 2003 10:59 am
Posts: 47
Judging from the comments in Hibernate blog, http://blog.hibernate.org/cgi-bin/blosxom.cgi + http://blog.hibernate.org/cgi-bin/pollxn.cgi?storypath=/Gavin%20King/perf-problems.html , I am not alone in this Session use confusion.

After your comments about Session being tied to a pooled thread being BAD, and the need for tying Session to a user(id), I am wondering if http://hibernate.org/42.html (Thread Local Session pattern page) is correct, or whether it represents an anti-pattern?

Thanks,
Otis


Top
 Profile  
 
 Post subject:
PostPosted: Wed Jan 28, 2004 10:24 am 
Hibernate Team
Hibernate Team

Joined: Mon Aug 25, 2003 9:11 pm
Posts: 4592
Location: Switzerland
We have about 40 pages in our book about "Session granularity and transactions", so this is a complex topic. Let us finish that and I'll post a shorter version on our Wiki highlighting the key points soon...

_________________
JAVA PERSISTENCE WITH HIBERNATE
http://jpwh.org
Get the book, training, and consulting for your Hibernate team.


Top
 Profile  
 
 Post subject:
PostPosted: Wed Jan 28, 2004 10:37 am 
Regular
Regular

Joined: Tue Aug 26, 2003 3:09 pm
Posts: 58
With the Thread Local Session pattern the thread local variable should be cleared at the end of each web request. There is no way to gaurantee that a user's web requests will be handled by the same thread over and over again. If you leave the thread local variable in the thread, and that thread is then used to handle another user's web request, you've just handed over one user's hibernate session to another user. Not good!

Joe


Top
 Profile  
 
 Post subject:
PostPosted: Wed Jan 28, 2004 10:55 am 
Hibernate Team
Hibernate Team

Joined: Mon Aug 25, 2003 9:11 pm
Posts: 4592
Location: Switzerland
Just wrote down the most important:

http://www.hibernate.org/Documentation/ ... ransaction

_________________
JAVA PERSISTENCE WITH HIBERNATE
http://jpwh.org
Get the book, training, and consulting for your Hibernate team.


Top
 Profile  
 
 Post subject:
PostPosted: Wed Jan 28, 2004 10:57 am 
Beginner
Beginner

Joined: Wed Dec 03, 2003 10:59 am
Posts: 47
Christian:

That would be great, I am looking forward to it!

Joe:

What exactly do you mean by 'clear the Session'? Which Session method should be called at the end of the user request? .close()?

Thanks,
Otis


Top
 Profile  
 
 Post subject:
PostPosted: Wed Jan 28, 2004 11:01 am 
Senior
Senior

Joined: Wed Aug 27, 2003 6:04 am
Posts: 161
Location: Linz, Austria
I'll post two of my questions from my comments on Gavin's blog here too. They are definitely clarifiable within a post rather than a whole book chapter ;-)

1. What about method-level transactions in a layered architecture, i.e. "session-per-business-method-transaction", as applied with EJB CMT or Spring's transaction management?

2. What about "session-per-web-request-with-multiple-business-method-transactions-and-closing-after-view-rendering", i.e. the "Open Session in View" pattern?

The former seems unavoidable in a layered architecture, as there is no such thing as an "application transaction" when working at the business layer interface level (respectively, "application transactions" correspond to transactions at the business method level).

The latter is what the "Open Session in View" pattern implies, possibly with variations like one transaction per web request, to be committed after the controller has finished, with the Session closed after view rendering (to allow for lazy loading).

I guess what's most confusing is the following sentence from the blog:
Quote:
An application transaction is a "unit of work from the point of view of the user"; it spans multiple requests and multiple database transactions.

The most important point is: What's a "request" here?

In general, I object to managing resources like a Hibernate Session in the user interface layer. This should really be dealt with below the business layer demarcation line. Even "Open Session in View" can be applied without affecting application code in the user interface layer, as shown by Spring's OpenSessionInViewFilter/Interceptor.

Juergen


Top
 Profile  
 
 Post subject:
PostPosted: Wed Jan 28, 2004 11:05 am 
Regular
Regular

Joined: Tue Aug 26, 2003 3:09 pm
Posts: 58
otis wrote:
What exactly do you mean by 'clear the Session'? Which Session method should be called at the end of the user request? .close()?


Sorry, I should have been clearer. I simply meant to null the thread local hibernate session variable so it won't be there on the next web request. It is ok to keep it in the http session if that fits with your strategy. Just don't keep it in a thread local variable for more than the life of a single web request.

Joe


Top
 Profile  
 
 Post subject:
PostPosted: Wed Jan 28, 2004 11:06 am 
Hibernate Team
Hibernate Team

Joined: Mon Aug 25, 2003 9:11 pm
Posts: 4592
Location: Switzerland
Juergen, check the page I just created on the Wiki and add to it.

_________________
JAVA PERSISTENCE WITH HIBERNATE
http://jpwh.org
Get the book, training, and consulting for your Hibernate team.


Top
 Profile  
 
 Post subject:
PostPosted: Wed Jan 28, 2004 11:12 am 
Senior
Senior

Joined: Wed Aug 27, 2003 6:04 am
Posts: 161
Location: Linz, Austria
OK, Christian, I see that you just answered my question regarding "requests" and "application transactions" (5 minutes before I hit "Submit")...

So my second pattern is basically "session-per-request" (Gavin's blog) respectively "session-per-thread" (your document). Would be good to settle on one term, I guess :-)

Still, my first one - "session-per-business-method-transaction" - is worth mentioning, as this is what you are concerned with in a business layer, be it with EJB CMT or with Spring's transaction management. Your current pattern discussion is very web-app-centric...

Note that a web controller might invoke multiple business methods for one web request. You'll get multiple (very few) Hibernate Sessions per request in that case. Your current patterns do not cover this case: This is still far from "session-per-operation", as we're talking about coarse-grained self-contained business transactions here.

Juergen


Top
 Profile  
 
 Post subject:
PostPosted: Wed Jan 28, 2004 11:15 am 
Hibernate Team
Hibernate Team

Joined: Mon Aug 25, 2003 9:11 pm
Posts: 4592
Location: Switzerland
Well, just add it :)

_________________
JAVA PERSISTENCE WITH HIBERNATE
http://jpwh.org
Get the book, training, and consulting for your Hibernate team.


Top
 Profile  
 
 Post subject:
PostPosted: Wed Jan 28, 2004 11:18 am 
Senior
Senior

Joined: Wed Aug 27, 2003 6:04 am
Posts: 161
Location: Linz, Austria
Hmmm, the Wiki page doesn't work anymore... I'll be happy to add my stuff as soon as the page works again.

BTW, I appreciate your efforts to clarify these important issues! Nevertheless, we should try to avoid unnecessary confusion.

Juergen


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

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.