-->
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.  [ 23 posts ]  Go to page 1, 2  Next
Author Message
 Post subject: Thread local session question
PostPosted: Fri Feb 20, 2004 7:46 pm 
Regular
Regular

Joined: Wed Sep 03, 2003 9:56 pm
Posts: 58
I've been reviewing session management strategies in an effort choose the correct one.

I've got a thick-client app talking directly to a database. In an effort to keep my UI responsive, I spawn background threads to load and save data to/from the database. I've been using an 'open session->load/save objects->close session' model, and am suffering (performance-wise) as a result.

Since this is a single-user application, I'm concidering a singleton session, synchronized to make it threadsafe. However, it seems that perhaps I should use the TLS pattern, but I'm concerned about having objects loaded by different sessions, should two database io threads happen to run concurrently.

Is there a standard pattern for such a (client/server) application? I've seen lots of discussion regarding N-Tier applications and TLS.

I did this wrong once, I just want to make sure I get it right this time, so any help would be greatly appreciated.


Top
 Profile  
 
 Post subject:
PostPosted: Sat Feb 21, 2004 3:22 am 
Regular
Regular

Joined: Tue Sep 09, 2003 9:37 pm
Posts: 56
Location: Ogden, Utah, USA
I think the thread-local session is mostly used for Web applications.

This is a good article on the length of a session:
http://hibernate.bluemars.net/168.html

Pay attention to the "application transaction" explanation. It's a good rule of thumb for the length that you keep a session around.

Good luck!
Jenica


Top
 Profile  
 
 Post subject:
PostPosted: Sat Feb 21, 2004 5:26 am 
CGLIB Developer
CGLIB Developer

Joined: Thu Aug 28, 2003 1:44 pm
Posts: 1217
Location: Vilnius, Lithuania
I think you do not need ThreadLocal if you start thread yourself.
Use base class for all threads:

public abstract class BaseRunnable implements Runnable{

private Session session;

public fianal void run(){

try{

doRun();

}fianally{

commitAndClose();
}

}

/**
* All threads in application must implement this method (abstract method),
* "getSession" must be used to open session,
* It is application error to commit or close session session in this method, base class doe's it in "run" (final method)
*/

protected abstract void doRun();

/*
* it can return wrapper to make sure close/commit throws exception,
* detect broken contract.
*/
protected Session getSession(){
if(session == null){
session = openSession();
}
return session ;

}


}


Top
 Profile  
 
 Post subject:
PostPosted: Sat Feb 21, 2004 6:40 am 
Hibernate Team
Hibernate Team

Joined: Tue Sep 09, 2003 2:10 pm
Posts: 3246
Location: Passau, Germany
Thick client apps are allways a bit of a pain, particulary because it is really not easy to figure out where one "buisness transaction" starts and ends. One important thing to remember is, Sessions are not thread safe. So a singleton session is not a good approach if you are working with multiple threads.

IMHO the approach you have been using is not that bad, why do you loose so much performance? Sessions are really lightweight so constructing them should not be that bad ...

If you use a ThreadLocal Session for your data access threads, you will pretty much get the same pattern, or are your Threads doing lots of open/save/close cycles?


Top
 Profile  
 
 Post subject:
PostPosted: Sat Feb 21, 2004 2:04 pm 
Regular
Regular

Joined: Wed Sep 03, 2003 9:56 pm
Posts: 58
I described the symptoms I was experiencing in a recent posting:

http://forum.hibernate.org/viewtopic.php?t=928208

The response was that my session management strategy (i.e. open/read/close) was the source of my redundant data problem.

In a single-user, thick-client application, it seems that a synchronized, singleton session pattern might be the best approach.


Top
 Profile  
 
 Post subject:
PostPosted: Sun Feb 22, 2004 1:01 am 
Hibernate Team
Hibernate Team

Joined: Tue Aug 26, 2003 7:19 pm
Posts: 2364
Location: Brisbane, Australia
I don't think so - if you have an exception then the session becomes invalid. You then have to manage this situation before another transaction can be started. Its easier to throw it away (after the rollback). It best to use boundaries that represent the unit-of-work. In most cases these are represented by an event handler. In the case of spawning threads to do the background work then TLS pattern is the best approach (but swing itself is not thread safe so you have more then hibernate's session object to worry about here).


Top
 Profile  
 
 Post subject:
PostPosted: Sun Feb 22, 2004 2:42 pm 
Regular
Regular

Joined: Wed Sep 03, 2003 9:56 pm
Posts: 58
I'm certainly not opposed to using the TLS pattern. My interest is in using the 'correct' session management pattern, whatever that may be.

Perhaps you can help me to understand how TLS might support lazy loading in the following circumstance:

The user opens/displays a 'view' that provides for navigation of complex object graphs stored in the database. A background thread is spawned to load the object graphs. If I dispose of the session object when the loader thread is done, then I lose the benefit of lazy loading during object navigation within the view.

This is the primary issue I set out to resolve. However, I'm also concerned about the following situation:

The user modifies portions of the object graph and clicks [Save]. Now, a new background thread, with it's new session object will be required to persist an object graph loaded by a different session object. My concern is that this will lead to inefficient updates.

Thanks again for responding.
-Mitch


Top
 Profile  
 
 Post subject:
PostPosted: Tue Feb 24, 2004 4:32 pm 
Hibernate Team
Hibernate Team

Joined: Sun Sep 14, 2003 3:54 am
Posts: 7256
Location: Paris, France
Using TLS in your case is useless.
sharing session between different threads sucks unless you synchronize it.

I you can't/don't want to synchronize, you should consider using a second-level cache to fit your needs.
To avoid extra updates, consider using version checking or dirty optimistic-lock. You'll have an extra read, but It may not matter in your case (graph update).

_________________
Emmanuel


Top
 Profile  
 
 Post subject:
PostPosted: Wed Feb 25, 2004 3:52 am 
Newbie

Joined: Mon Feb 23, 2004 3:54 am
Posts: 3
Hi!

I'm also thinking about a think client application which will operate directly with the business logic layer to read, update and create data.

Although the persitence handling should be covered by the business layer isn't it possible to delegate the session management to some kind of system layer where the display and interaction layer ('view') must obtain a session for accessing the business layer?

This way every view (dialog, wizard...) has its own sessions and I'm able to keep a session long enough open while lazy loading is performed.

Is this approach acceptable?

Thanks,
Gunnar


Top
 Profile  
 
 Post subject:
PostPosted: Wed Feb 25, 2004 8:40 am 
Hibernate Team
Hibernate Team

Joined: Sun Sep 14, 2003 3:54 am
Posts: 7256
Location: Paris, France
Beware stale datas

_________________
Emmanuel


Top
 Profile  
 
 Post subject:
PostPosted: Wed Feb 25, 2004 1:15 pm 
Newbie

Joined: Mon Feb 23, 2004 3:54 am
Posts: 3
Does it mean the cache of a session is not updated when updates are performed in a transaction within another session in the same VM (I don't want to ask about clustering)?


Top
 Profile  
 
 Post subject:
PostPosted: Wed Feb 25, 2004 1:20 pm 
Hibernate Team
Hibernate Team

Joined: Thu Dec 18, 2003 9:55 am
Posts: 1977
Location: France
hibernate sessions are independant, think session as "business unit" cache, if you use a second level cache, all hibernate sessions will work with the second level cache, i think this is the best solution for you: TLS + second level cache (ehcache is easy to use)


Top
 Profile  
 
 Post subject: Lazy loading in multithreaded "thick client"
PostPosted: Wed Mar 10, 2004 11:13 am 
Newbie

Joined: Tue Oct 21, 2003 9:36 am
Posts: 11
Location: Munich, Germany
Hi,

I read many (if not all) the forum posts regarding lazy loading in thick clients and session strategies / session synchronization. I think I understood why the session is not threadsafe, why synchronizing on the session is usually not considered good practice and why the DB should cope with concurrency etc. Nevertheless, I think I have a case where the "easiest" solution would be to fully synchronize on the session. The problem here is synchronizing the use of the session for lazy loading of collections.

My single-user Swing app uses a tree to view an object graph. Loading the complete graph at once takes much too long (I tried it), so I declare all collections as lazy. When the user expands a node, the tree spawns an extra thread to load the data. My session strategy is best described as "session-per-application-transaction". Basically, I use a new session whenever a new object graph is loaded into the tree. The session stays open, allowing for transparent lazy loading. The user may also edit individual objects from the graph. On clicking [save] I flush and commit the current session from within a thread spawned by our GUI framework when clicking a button.

Problem:
Flush() and commit() happen in a different thread from the lazy loading. Most of the time everything works fine but from time to time I get error messages from Hibernate like the ones shown below. I synchronize all explicit session operations (flush etc.) but I don't know how to synchronize lazy loading on the session object. I read http://forum.hibernate.org/viewtopic.php?t=925435 and agree with all advice given there, but I think my situation is different.

Is it possible to have lazy initialization synchronize on the session held by the lazy collections? Thanks for any kind of help.

Kay

I use Hibernate 2.1.2.

Here's error message 1:
Code:
10-Mrz-2004 13:52:00 ERROR [Worker 4] |  sf.hibernate.AssertionFailure | an assertion failure occured (this may indicate a bug in Hibernate, but is more likely due to unsafe use of the session)
net.sf.hibernate.AssertionFailure: Hibernate has a bug processing collections
   at net.sf.hibernate.impl.SessionImpl$CollectionEntry.postFlush(SessionImpl.java:365)
   at net.sf.hibernate.impl.SessionImpl.postFlush(SessionImpl.java:2800)
   at net.sf.hibernate.impl.SessionImpl.flush(SessionImpl.java:2205)
   at de.continental.fits.hibernate.FitsDatastoreManagedSessions$FlushCommand.perform(FitsDatastoreManagedSessions.java:645)
   at de.continental.fits.hibernate.FitsDatastoreManagedSessions.perform(FitsDatastoreManagedSessions.java:540)
   at de.continental.fits.hibernate.FitsDatastoreManagedSessions.commit(FitsDatastoreManagedSessions.java:583)
   at de.continental.fits.datastore.UnitOfWork.commit(UnitOfWork.java:157)
   at de.continental.fits.gui.base.MainModel.commit(MainModel.java:112)
   at de.continental.fits.gui.forms.MeasurementEditController.actionSave(MeasurementEditController.java:137)
   at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
   at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
   at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
   at java.lang.reflect.Method.invoke(Method.java:324)
   at de.bea.xui.util.MethodCallReflection.invoke(MethodCallReflection.java:32)
   at de.bea.xui.call.parser.XuiAccessMethod.getValue(XuiAccessMethod.java:211)
   at de.bea.xui.call.parser.XuiDefaultCall.getValueNoErrorChecking(XuiDefaultCall.java:89)
   at de.bea.xui.XuiThreadManager$WorkerThread.run(XuiThreadManager.java:281)


And error message 2:
Code:
java.lang.NullPointerException
   at net.sf.hibernate.collection.Set.size(Set.java:107)
   at java.util.ArrayList.<init>(ArrayList.java:132)
   at de.continental.fits.gui.base.TestPlanTabModel.getTestPlanChildren(TestPlanTabModel.java:270)
   at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
   at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
   at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
   at java.lang.reflect.Method.invoke(Method.java:324)
   at de.bea.xui.util.MethodCallReflection.invoke(MethodCallReflection.java:32)
   at de.bea.xui.call.parser.XuiAccessMethod.getValue(XuiAccessMethod.java:211)
   at de.bea.xui.call.parser.XuiDefaultCall.getValue(XuiDefaultCall.java:109)
   at de.bea.xui.call.parser.XuiDefaultCall.getValue(XuiDefaultCall.java:80)
   at de.bea.xui.component.XuiTree$XuiTreeCoreModel.retrieveChildren(XuiTree.java:1044)
   at de.bea.xui.component.XuiTree$XuiTreeCoreModel.getChildren(XuiTree.java:957)
   at de.bea.xui.component.XuiTree$XuiTreeCoreModel.getIndexOfChild(XuiTree.java:970)
   at de.bea.xui.component.XuiTree$XuiTreeCoreModel.getPath(XuiTree.java:1188)
   at de.bea.xui.component.XuiTree$XuiTreeCoreModel.getPath(XuiTree.java:1178)
   at de.bea.xui.component.XuiTree$XuiTreeRootChanger.work(XuiTree.java:1399)
   at de.bea.xui.component.XuiTree$XuiTreeWorker.getValue(XuiTree.java:1264)
   at de.bea.xui.component.XuiTree$XuiTreeWorker.getValueNoErrorChecking(XuiTree.java:1278)
   at de.bea.xui.XuiThreadManager$WorkerThread.run(XuiThreadManager.java:281)


Top
 Profile  
 
 Post subject:
PostPosted: Wed Mar 10, 2004 12:16 pm 
Regular
Regular

Joined: Wed Sep 03, 2003 9:56 pm
Posts: 58
My session synchronization strategy was a bit more inclusive.

I serialize access to a singleton Session object through the use of a HibernateSession.getCurrent() method (HibernateSession is my own implmementation of the singleton pattern). This method guarantees single-threaded access to the (singleton) Session object (using Session.wait()/Session.notify() semantics).

A thread uses the session in the following manner:

o Access the Session object via HibernateSession.getCurrent()
o Interact with the Session object as necessary.
o Release the Session object via HibernateSession.release()

If a thread is currently using the Session object, any subsequent calls to HibernateSession.getCurrent() will block. As soon as the owning thread releases the Session object (via HibernateSession.release()), one of the waiting threads will be awakened and granted access to the Session object.

FWIW, I have not had time to fully test this model. I have implemented the code and the prelimary tests look promising. I haven't seen any exceptions as yet. Your your mileage may vary.


Top
 Profile  
 
 Post subject:
PostPosted: Wed Mar 10, 2004 12:50 pm 
Newbie

Joined: Tue Oct 21, 2003 9:36 am
Posts: 11
Location: Munich, Germany
But what about lazy initialization? As far as I understand, Hibernate's lazy collections carry around a reference to the Session they were created under and use it to transparently retrieve data from the DB when the collection is accessed. I don't know how I can force the use of HibernateSession.getCurrent() (or my equivalent) inside Hibernate's lazy initialization mechanism.

I think I need a Hibernate option "synchronize on Session object when doing lazy initialization". Hm, I can imagine Gavin's reaction on this suggestion :-)

Quote:
FWIW, I have not had time to fully test this model. I have implemented the code and the prelimary tests look promising. I haven't seen any exceptions as yet.

I'm curious if you experience any errors similar to mine when you start to use your model extensively.


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