I got some trouble loading a list of objects from my database using Hibernate and lazy=true mode. Hope that someone can help me out here.
I have a simple class here
Lazy Loading working or not has nothing to do with transaction boundaries. It only requires that the Session be open.
However, when the session is open depends on how you've actually set up the SessionFactory, which you did not tell us! There is config going on behind what SessionFactory.getCurrentSession()
actually does! If you're letting it go with the default version of ThreadLocalSessionContext
and not doing anything to manage the life cycle, it does indeed actually default to closing the session when you commit. (Hence the common conception that broadening transaction boundaries is the 'fix' for a lazy load exception.)
If you manage you own session life cycle with sessionFactory.openSession()
and session.close()
you will be able to lazy load fine within the session life cycle, outside transaction boundaries. Alternately you can provide a subclass of ThreadLocalSessionContext
that manages the session life-cycle with the boundaries you desire. There are also readily available alternatives such as the OpenSessionInView filter that can be used in web applications to bind the session life-cycle to the web request life cycle.
edit: You can also of course just initialize the list inside the transaction if that works for you. I just think that leads to really clunky APIs when you need either a new method signature of some kind of 'flag' parameter for each level of hydration of your entity. dao.getUser() dao.getUserWithMailAccounts() dao.getUserWIthMailAccountsAndHistoricalIds() and so on.
edit 2: You may find this helpful for different approaches to how long the session stays open/the relationship between session scope and transaction scope. (particularly the idea of session-per-request-with-detached-objects vs session-per-conversation.)
It depends on your requirements and architecture just how big a conversation actually is.
You need to wrap your entire process within a transaction.
So instead of starting and commiting the transaction in loadUserAccount, do it outside of that.
For example:
public void processAccount()
{
getSession().beginTransaction();
UserAccount userAccount = loadUserAccount("User");
Vector accts = userAccount.getMailAccounts(); //This here is lazy-loaded -- DB requests will happen here
getSession().getTransaction().commit();
}
Usually, you want to wrap your transaction around the entire unit of work. I suspect that your understanding of transactions is a little too fine grained.
The reason you're getting the exception might be that the transaction you load the data in is closed (and the session with it), i.e. you're working outside the session. Lazy loading is especially useful when working with entities in one session (or across sessions when correctly employing a second level cache).
AFAIK you can tell Hibernate to automatically open a new session for lazy loading but I didn't use that for a while and thus I'd have to look up how that works again.