-->
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.  [ 14 posts ] 
Author Message
 Post subject: Lazy Loading with detached objects
PostPosted: Thu Nov 10, 2005 3:46 pm 
Newbie

Joined: Thu Nov 10, 2005 3:11 pm
Posts: 8
I have a situation where a particular object is loaded in Session1 and being used again in Session2. (Session1 being the first servlet request and Session2 being the 2nd request. We are using Struts and the session-per-request pattern using filter).

(Note: I am using Hibernate 3 and all classes are by default lazy="true")

Here is the issue:

On the first request, an object A is created which has a many to one relationship with, say object B. B is present in the database and hence when A is created, I load B from the database and attach it to A. All these operations occur in a single Hibernate Session transaction.

Now when user tries to perform another operation on the same page (second request which opens another Session), I am trying to access object B but I get LazyInitializationException (owning session closed). I don't understand why it says Session is closed eventhough it is open during this time. I tried Hibernate.initialize(B) and now it doesn't throw the exception. So my question is, why didn't the object B get loaded in Session2 on request. Any help would be appreciated...

Thanks.


Top
 Profile  
 
 Post subject:
PostPosted: Thu Nov 10, 2005 4:33 pm 
Expert
Expert

Joined: Fri Aug 19, 2005 2:11 pm
Posts: 628
Location: Cincinnati
I am trying to get a grasp of what is going on. In Session 1 you load A which supposedly loads B. In session 2, you finally try to access B?

If this is the case, then you must not be loading B all the way in Session 1. If it is lazy=true, then Session 1 is loading a proxy to B, not the actual data. When you finally call A.getB() is when it tries to make a DB call and it says the owning session is closed (which was Session 1.)

_________________
Chris

If you were at work doing this voluntarily, imagine what you'd want to see to answer a question.


Top
 Profile  
 
 Post subject:
PostPosted: Thu Nov 10, 2005 4:39 pm 
Expert
Expert

Joined: Thu Dec 23, 2004 9:08 pm
Posts: 2008
Session1 could still be open, but if it's not accessible (e.g. in another thread) then it can't be used to initialize object B. That's why your call to initialize fixed it: it happened within a scope that had access to session1.


Top
 Profile  
 
 Post subject:
PostPosted: Thu Nov 10, 2005 4:40 pm 
Newbie

Joined: Thu Nov 10, 2005 3:11 pm
Posts: 8
Kochcp:

In session 1 I am not loading A, I am creating a new instance of A but B is foreign key to A hence I load B and attach it to object A during Session 1.

Hope this will explain better:

A page has a 'new button' to create a Node, on clicking the new Button I create a new instance of Node. This Node is a child to a Document object, so I load the Document object and set it on the Node (note that Node is not persistent yet). Before saving Node, we can add attributes to the Node, this is where session 2 comes into picture...during the process of adding the attributes (in Session 2) I have to access the Document object from Node..while accessing that, it gives me the exception...


Top
 Profile  
 
 Post subject:
PostPosted: Thu Nov 10, 2005 4:45 pm 
Newbie

Joined: Thu Nov 10, 2005 3:11 pm
Posts: 8
tenwit:

I don't understand how session 1 could be open, object B is accessed in 2 different servlet requests and each request has a session open and close calls.


Top
 Profile  
 
 Post subject:
PostPosted: Thu Nov 10, 2005 4:52 pm 
Expert
Expert

Joined: Thu Dec 23, 2004 9:08 pm
Posts: 2008
The language is confusing me here, but I think you're doing the classic web app stuff: session1 gets something, passes it around a response/request scope mechanism, then it comes back into business logic, where session2 is available. At this point, you're in a different thread to session1, so you cannot use session1's cache/pointers/dereferencing code to figure out what SQL to use in order to get the missing data. You have to use session2 for that, because that's the only one you have.

If this is the scenario you're dealing with, then you must detach the object when session1 is done with it, even if session1 isn't closed. Then when the object is made available to session2, it can re-attach the object. Alternatively, you can do just as you are doing at the moment: fully initialize all lazy links so that you don't have to worry about other sessions in the future.


Top
 Profile  
 
 Post subject:
PostPosted: Thu Nov 10, 2005 5:07 pm 
Newbie

Joined: Thu Nov 10, 2005 3:11 pm
Posts: 8
You are right about the classic web stuff...from what I understand, if an object is loaded using session1 it cannot be referenced using a different session (session2) unless it is evicted from session1 and reattached using session2. Is this statement true ? Why should the proxy be reinitialized for each session ?


Top
 Profile  
 
 Post subject:
PostPosted: Thu Nov 10, 2005 5:17 pm 
Expert
Expert

Joined: Thu Dec 23, 2004 9:08 pm
Posts: 2008
Because the useful de-proxying information is contained within the session. The objects that you pass around contain pointers into the session's cache of information concerning how to find the not-yet-initialized links. Different sessions have different caches of this information. If all the information was stored in each object, then they'd be much more heavyweight than they would be if you just fully initialized then in advance.


Top
 Profile  
 
 Post subject:
PostPosted: Thu Nov 10, 2005 5:28 pm 
Newbie

Joined: Thu Nov 10, 2005 3:11 pm
Posts: 8
Thanks for the information...so when we call Hibernate.initialize, it initializes the proxy to point to the current session...cool... Thanks again...Really appreciate your help...


Top
 Profile  
 
 Post subject:
PostPosted: Thu Nov 10, 2005 5:41 pm 
Expert
Expert

Joined: Thu Dec 23, 2004 9:08 pm
Posts: 2008
No, when you call initialize() it uses the current session to fully expand all lazy links. You can only do it using the session that created those lazy links. In your example, you can't use session2 to initialize your object that was loaded using session1. To initialize the object, you must use Session.lock() in session2, then call initialize: lock() effectively "re-proxies" the object in session2.


Top
 Profile  
 
 Post subject:
PostPosted: Thu Nov 10, 2005 5:52 pm 
Newbie

Joined: Thu Nov 10, 2005 3:11 pm
Posts: 8
Is there any other efficient way of doing it in this scenario, it looks like if I use Initialize then there would be no need to have the object set to lazy="true", I met as well have it false, correct ?


Top
 Profile  
 
 Post subject: Session.lock()
PostPosted: Thu Nov 10, 2005 6:07 pm 
Expert
Expert

Joined: Thu Dec 23, 2004 9:08 pm
Posts: 2008
You can set lazy="false", which gives you the added advantage of being able to use the nested objects at the UI, outside of either session.

However, for efficiency's sake (and assuming that you don't need those nested objects at the UI), just call Session.lock() on the object in session2. Ensure that you use the correct lock mode: if session1 has not detached the object, then you should not use session1 to write to the object, and only use LockMode.READ in session2. If you want to use session2 to write the object back to the DB, then detach the object in session1 before passing it back to the UI (Session.evict()), then use LockMode.UPGRADE.


Top
 Profile  
 
 Post subject:
PostPosted: Thu Nov 10, 2005 6:15 pm 
Expert
Expert

Joined: Fri Aug 19, 2005 2:11 pm
Posts: 628
Location: Cincinnati
Session.update is the usual way of reattaching a transient object to another session as it will persist any changes that were made to the object while it was detached (the user interaction part below).


in pseudocode you would want to do:
[code]
Session1 Begin

Session1.load(A)

Session1 End

-- user interaction stuff here
-- second request generated to get B's properties

Session2 Begin

Session2.update(A);
Hibernate.initialize(A.getB);

Session2 Close
[code]

_________________
Chris

If you were at work doing this voluntarily, imagine what you'd want to see to answer a question.


Top
 Profile  
 
 Post subject:
PostPosted: Thu Nov 10, 2005 7:24 pm 
Newbie

Joined: Thu Nov 10, 2005 3:11 pm
Posts: 8
Thanks Guys...


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