-->
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.  [ 15 posts ] 
Author Message
 Post subject: Web Tier causing multiple session object association problem
PostPosted: Mon Feb 02, 2004 10:40 am 
Newbie

Joined: Fri Sep 12, 2003 9:13 am
Posts: 10
Hi,

I have a normal web application where I store a User type of object in the Http Session. When the user accesses a page, I call a Session.lock() on this User object to reassociate it, to assist with any updates or retrievals of lazy loaded data.

The problem I have is that some pages may take a short time to load, and when a user clicks on a new page without waiting for the first page to return, I end up with a error on the user associating the collection with multiple sessions. (I'm calling lock with LockMode of NONE.)

Now, right now I'm fairly free with re-locking the User object.. should I not be? Theoretically I could dive down in the code and force a reassociation/lock right before a update needs to be performed.. but is this the recommended way?

My other concern is that I have some background threads that update the user data in the database periodically.. but if the user is stored in the session, it isn't getting updated. I could force the application to refresh the User object on each request.. and if it just hit the cache that would be ok.. but it always hits the database.

So.. any design advice or guidance on solving these problems?

(Quick note.. I'm pulling a session through Servlet Filters to ensure the session is available when rendering the JSP page, for any lazy loaded data. This session is consistent through the entire processing.)

thanks!


Top
 Profile  
 
 Post subject:
PostPosted: Mon Feb 02, 2004 11:15 am 
Hibernate Team
Hibernate Team

Joined: Mon Aug 25, 2003 9:11 pm
Posts: 4592
Location: Switzerland
For your "updating" problem: If you want fresh data from the database, you have to hit the database, not the cache.

So, your real problem is that an "incomplete" request/response cycle breaks your application. I actually don't think that this is a problem we can solve, because it your web application should close resources (the first Session) if the response is not completely send. That means you have to close the Session in your Servlet filter in a finally{} clause and make sure that it is always called.

Don't use a LockMode (thats database level-shared or pessmistic locks) if you don't have to (doesn't solve your problem).

Use update() if the User has been modified _between_ requests (i.e., outside of any Session or Transaction scope. Use lock(<no LockMode>) if it hasn't been modified.

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


Top
 Profile  
 
 Post subject:
PostPosted: Mon Feb 02, 2004 11:43 am 
Newbie

Joined: Fri Sep 12, 2003 9:13 am
Posts: 10
With the object being associated with multiple sessions, it is certainly not a hibernate problem.. its just doing what is asked of it. But this would presumably be a common problem if objects are being associated with sessions consistently (say, each page) and the user clicks ahead without waiting for results..

My servlet filter is very careful about closing all sessions.. so I don't think thats a problem. If the user is methodical and not in a hurry, they don't encounter any problems.

I'm trying to see if there are any recommended solutions for this. I was trying to pull the object from my session and simply reassociate it with the LockMode.NONE.. so minimal locking level here.

I can narrow the scope of the possible problem by narrowing in my lock.. but I don't see how to totally remove the problem.

I guess I could switch around a bit.. just store a value object in my session, and force the session lock's only when absolutely necessary.. I would loose the lazy loading advantage, but thats not too big of a deal. Do people typically store hibernate-managed data objects in their sessions?


Top
 Profile  
 
 Post subject:
PostPosted: Mon Feb 02, 2004 11:59 am 
Hibernate Team
Hibernate Team

Joined: Mon Aug 25, 2003 9:11 pm
Posts: 4592
Location: Switzerland
So, the first thread runs no matter what happens on the client and executes all code (and closes the Session at the end).

Your problem seems to be the second request that uses the same object in another thread and Session, possibly at the same time. The solution is to prevent that second request from executing while the first one still runs.

There are some techniques that prevent double clicks (by some weird checking of one-time lease numbers for each request from each page), but your problem is more interesting.

Actually, I have no solution, but I'd be interested myself. Well, maybe I should look at that for more than 2 minutes...

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


Top
 Profile  
 
 Post subject:
PostPosted: Mon Feb 02, 2004 12:06 pm 
Newbie

Joined: Fri Sep 12, 2003 9:13 am
Posts: 10
To give you an example.. lets say I have two menu options..

The first option is going to generate a calendar of information based on stored and calculated data.. (perhaps the user has certain constraints that limit what data should be visible.. and then the system needs to calculate additonal data based on the constraints..) So this request could say perhaps 5 or 10 seconds.

The user, being used to their fast paced life gets bored with that and clicks on a different menu item instead.

The servlet engine happily keeps thread 1 going with the calendar and kicks in thread 2 to handle the subsequent request.

Since I'm associating the User object (from the Http Session) back with my hibernate Session on each page, I get a small muffled whump sound as I get an exception thrown.

The user isn't really doing anything they wouldn't normally do. In fact.. I can simply the example above.. they click on the menu navigation as a double click.. or click again when it takes a few seconds.. normal sorts of activity.

If I keep all hibernate data out of the session and just store a flattened view object of the user, then I would limit all of my locking and session associations to those times where its absolutely necessary. I'm not doing that now.. but I don't see a good way to otherwise solve this problem.

Its not even a transactional issue.. just doing the Session.lock(user, LockMode.NONE) happily blows it up.. unless I'm missing something there.

Thanks for your reply's on this.. any insight would be wonderful!


Top
 Profile  
 
 Post subject:
PostPosted: Mon Feb 02, 2004 12:07 pm 
CGLIB Developer
CGLIB Developer

Joined: Thu Aug 28, 2003 1:44 pm
Posts: 1217
Location: Vilnius, Lithuania
elemur wrote:

I guess I could switch around a bit.. just store a value object in my session, and force the session lock's only when absolutely necessary.. I would loose the lazy loading advantage, but thats not too big of a deal. Do people typically store hibernate-managed data objects in their sessions?

Yes, it is better to store just id or some thread safe data structure in http session, but it must be trivial to solve this problem.
Workaround can be some attribute in http session :

void filter(..){

try{

if(session.getAttribute(NAME) != null ){
request.sendRedirect(url);
}

session.setAttribute(NAME,"");
chain.doFilter(..);

}finally{

session.removeAttribute(NAME);


}




}


Top
 Profile  
 
 Post subject:
PostPosted: Mon Feb 02, 2004 12:10 pm 
Hibernate Team
Hibernate Team

Joined: Mon Aug 25, 2003 9:11 pm
Posts: 4592
Location: Switzerland
Well, thats a workaround that would send the user to a new page if he clicks too fast. This new page should have no Hibernate Session or reattached User, otherwise its the same problem again. It's a workaround for sure, but I still think I'm missing something and there must be a "real" solution.

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


Top
 Profile  
 
 Post subject:
PostPosted: Mon Feb 02, 2004 12:22 pm 
Hibernate Team
Hibernate Team

Joined: Mon Aug 25, 2003 9:11 pm
Posts: 4592
Location: Switzerland
Can't find a solution, objects in a the HttpSession are by nature not thread-safe, so we can not control the reattachment of an object to only a single Hibernate Session. Thats really annoying because it breaks some of the nice things you can do with detached objects.

Apparently, some web containers give you an IOException on a PrintWriter if the underlying HTTP connection dies (this is the case here in the first request). I can't think of a good way to use this, however. The proposed workaround is probably the best.

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


Top
 Profile  
 
 Post subject:
PostPosted: Mon Feb 02, 2004 12:26 pm 
Newbie

Joined: Fri Sep 12, 2003 9:13 am
Posts: 10
I agree.. I could do some sort of meta-locking to check this.. or just handle the session association exception in a different way.. but both requests are essentially valid.. its just that the user didn't wait to see the results of their first request.

Imagine if you were doing a search on google and clicked to the dirctory, and got an error "Sorry.. you clicked too fast.. go back and try again.."

I guess the underlying problem is that having a hibernate managed object in the Http Session has the potential to be associated to multiple Hibernate sessions.. no matter what. So if I want to avoid any contention issues like this.. I need to make a data transfer object and drop it in the session instead.. and just convert to hibernate object when updating/persisting. Then, the scope of the hibernate object is always limited to a single thread/session.. and even if I got two servlet threads to overlap on updating that hibernate object, the database locks could help to deal with that.

This isn't my preferred way, since I would like more data lazy loaded.. but so far it seems like it will be the least likely to blow up on me during use.

(And just to note.. I'm still only referring to objects in the Http Session.. other hibernate objects work just fine.. but they only have a lifetime of the request, and therefore live within my filter contained hibernate session.. so no problems there..)

thanks


Top
 Profile  
 
 Post subject:
PostPosted: Mon Feb 02, 2004 12:33 pm 
Hibernate Team
Hibernate Team

Joined: Mon Aug 25, 2003 9:11 pm
Posts: 4592
Location: Switzerland
Just a note: You don't have to explicitely lock (or even use an exclusive lock) to ensure data integrity. Hibernate has automatic versioning if you have a version property mapped. So any concurrent changes to a Hibernate object would be resolved at commit time, by comparing versions. Thats much more efficient than expensive locks.

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


Top
 Profile  
 
 Post subject:
PostPosted: Mon Feb 02, 2004 12:47 pm 
Newbie

Joined: Fri Sep 12, 2003 9:13 am
Posts: 10
Right.. the only read I'm calling lock is to reassociate the object with the current session.. I've never had locking problems with hibernate in a database lock sense..


Top
 Profile  
 
 Post subject:
PostPosted: Mon Feb 02, 2004 1:06 pm 
CGLIB Developer
CGLIB Developer

Joined: Thu Aug 28, 2003 1:44 pm
Posts: 1217
Location: Vilnius, Lithuania
christian wrote:
Well, thats a workaround that would send the user to a new page if he clicks too fast. This new page should have no Hibernate Session or reattached User, otherwise its the same problem again. It's a workaround for sure, but I still think I'm missing something and there must be a "real" solution.


No, it can send user to the same page, with the same parameters.
It can work like "synchronize", but will not waste thread on server.:

void filter(..){

try{

if(session.getAttribute(NAME) != null ){
response.sendRedirect(request.getRequestUrl() + request.getQueryString() );
return;
}

session.setAttribute(NAME,"");
chain.doFilter(..);

}finally{

session.removeAttribute(NAME);


}

it is possible to send heater like this:
"Refresh: 2;URL=$url" or HTML with
<META HTTP-EQUIV="Refresh" CONTENT="2;URL=$url">

But this will not work for file uploads (it can not "POST").


Top
 Profile  
 
 Post subject:
PostPosted: Tue Feb 03, 2004 12:31 pm 
Hibernate Team
Hibernate Team

Joined: Mon Aug 25, 2003 9:11 pm
Posts: 4592
Location: Switzerland
So, basically this workaround says: "Clients use the HttpSession with serialized access, and retry if another thread currently runs, until the other thread finished his work". Thats a real hack :)

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


Top
 Profile  
 
 Post subject:
PostPosted: Tue Feb 03, 2004 12:58 pm 
Newbie

Joined: Fri Sep 12, 2003 9:13 am
Posts: 10
Yeah.. its interesting, but not really something I can work into my app.

As far as my problem.. I don't have a real answer on my original problem, so I've reduced the scope of the objects being associated with a given session. So my User object (hibernate managed data) is left stale in the session until an update process comes along.. then I do update's and the occasional refresh to get things back in sync for that limited scope. Since I'm not reassociating the User back with the Session (hibernate) on each page, the scope of the conflicts between repeat requests is more limited. I will need to put in double-click protection on forms, etc.. though..

One related problem I forsee is that, if a user logs in from multiple locations I could end up with competing User objects in different sessions. Again, this isn't hibernate's fault or problem per-se.. its just storing data I ask for. But.. if I am storing hibernate associated objects in a session.. it seems like I need some factory store or something to ensure the multiple sessions reference the same object.

(Again.. this is sort of your boundry case behavior.. but I always like to test these sorts of things..)


Top
 Profile  
 
 Post subject:
PostPosted: Tue Feb 03, 2004 1:02 pm 
Hibernate Team
Hibernate Team

Joined: Mon Aug 25, 2003 9:11 pm
Posts: 4592
Location: Switzerland
No, in the last case you describe you should not synchronize anything in the application. That would be an expensive lock and a bottleneck. Just use the versioning system.

If two instances in two Sessions are in fact the same database row, the version of that row is used to detect stale data. If Session A commits changs earlier to that row, Session B will get an exception at commit. You can then decide if you'd like to overwrite it (or let the user decide) or simply show an error message ("Someone has modified it while you edited it!"). If you don't use versioning, Session B will overwrite the changes made by A without an exception.

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


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 15 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.