Tuesday, May 31, 2011

Hibernate's Lazy Initialization

Exception in thread "main" org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: <CLASS>.<METHOD>, no session or session was closed

If you've ever received this error from Hibernate, you're not alone.  It happens because of Hibernate's "Lazy" initialization for joined relations.  It's a common problem because it occurs when you close the Hibernate session before you've accessed all the members that you need from the class --- which happens when you try to abstract the Object-Relational Mapping layer from the higher layers of your application.

For example: a Student class has a list of Classes.  Logically, you add the Hibernate queries for students to the Student class.  Your code likely has the following structure:
  • Create a new session
  • Make the query
  • Close the session
  • Return the result
Unfortunately, if you return the Student class, then query getClassList() --- you end up with a "Lazy Initialization Error."  This is because hibernate only does a query for the class list when you explicitly ask for it.

Here's a way for you to keeps higher-level classes from knowing about Hibernate, while maintaining the ability to create/destroy Hibernate session(s) appropriately:

   
  2 import org.hibernate.Session;
  3 import org.hibernate.SessionFactory;
  4 import org.hibernate.cfg.Configuration;
  5               
  6 /**           
  7  * Keeps track of Hibernate session for us
  8  */           
  9 public abstract class Queryable {
 10               
 11    /**        
 12     * Hibernate session
 13     */  
 14    private static Session session = null;
 15         
 16    /**  
 17     * Get (or create a new) hibernate session
 18     */
 19    public static Session getSession() {
 20       if( session == null ) {
 21          SessionFactory sessionFactory = new
 22            Configuration().configure().buildSessionFactory();
 23          session = sessionFactory.openSession();
 24       }
 25       return session;
 26    } 
 27   
 28    /**
 29     * Manually close the session.
 30     */
 31    public void closeSession() {
 32       if( session != null ) {
 33          session.close();
 34          session = null;
 35       } 
 36    } 
 37   
 38 }

Simply make the Student class extend Queryable and use getSession() everywhere you would have created or referenced the Hibernate session.  Don't forget to close the session when you're done with the object!

Also, thanks to the following website that gave me some insight into the problem:
http://www.javalobby.org/java/forums/t20533.html

No comments:

Post a Comment