views:

279

answers:

2

I have a domain object that has an attribute which is a collection containing another domain object. This is accomplished using a hibernate mapping (which eventually performs a join on another table). Hibernate, by default, seems to lazily instantiate this collection. This turns out to be a great thing because, depending upon what I need displayed, I do not always need the collection to be loaded.

My issue is the following: when writing my hibernate queries (in my DAOs), I use the following to open / close a Session:

Session session = getSessionFactory().openSession();
//query goes here using the session var
session.close();

The problem is: when Hibernate finally comes around to lazily loading my collection, the Session has long been closed! How can I get around this? I assume that I have to close the session as I am doing...

This is the error I get:

SEVERE: failed to lazily initialize a collection of ...
+1  A: 

I understand that you open and close the session for each DAO operation. You could instead use one and the same session by all DAOs, opened sometime during intialization and closed at shutdown. Note that the Hibernate Reference mentions "session per operation" as an antipattern:

"Do not use the session-per-operation antipattern: do not open and close a Session for every simple database call in a single thread."

In brief, a session should enclose a unit of work. This may be a single user request (possibly including multiple queries), or a longer conversation (including multiple screens with their own (groups of) queries). In the latter case there is reason to think about not keeping the session ( = transaction) open for extended periods of user think time, but yours does not sound like this case to me.

If you close the session, your domain object becomes detached. You could open a new session, tie your object to it then load the collection, but to me it looks quite a hassle.

Péter Török
Thanks. I considered doing this. I'm just not sure what it would look like (where to initialize and where to close etc.). Also is this standard practice? I'm sure I'm not the first one to have this issue so there must be a best practice way of handling the session...
es11
+3  A: 

If this is occurring within a webapp, then the easy fix for this is to use an OpenSessionInViewInterceptor or OpenSessionInViewFilter. These delay the closing of the session until the whole request has completed, allowing you to navigate lazy associations when rendering the view.

A more general solution is to rewrite your queries so that they explicitly specify which associations should be fetched up-front. This lets you keep the associations lazy by default, while at the same time catering for special cases where you want them fetched eagerly. See the description of "fetch joins" in the Hibernate docs.

A "fetch" join allows associations or collections of values to be initialized along with their parent objects using a single select. This is particularly useful in the case of a collection. It effectively overrides the outer join and lazy declarations of the mapping file for associations and collections

skaffman
Does the OpenSessionInViewXYZ work with other MVC frameworks or just Spring MVC?
marklai
Thanks, I have a question though: The OpenSessionInViewInterceptor/Filter may be what I need, but you mentioned that it delays closing the session until the whole request has completed. What if one of my views never forces the collection to be loaded..then isn't it possible that the session will never be closed if the user doesn't navigate to a page which forces the initialization (and isn't this a problem?)?
es11
..actually I think I was confusing what is meant by "request"
es11
@marklai Open Session in View is a pattern (https://www.hibernate.org/43.html) that can be used with any web framework, it is absolutely not Spring specific.
Pascal Thivent
@es11: Yes, I meant the HTTP request. The filter will close the session regardless of what your view does.
skaffman
@Pascal: Yes, but the Spring `OpenSessionInViewFilter` implementation *is* Spring-specific.
skaffman
Oh, sure, the Spring implementation of the pattern is Spring specific. I think I misread the question. Sorry for the confusion.
Pascal Thivent