Friday, April 13, 2007

Lazy Initialization Exception in Hibernate

I am totally frustrated when getting this exception in my Leave Application. B'coz My friend who has done a project in Hibernate using some wrappers said he has never ever come across this kind of problem because of the wrappers. But after googling, i found out this is one of the common problem for those who are new to hibernate.

Finally i got the solution, why this kind of error occured. Would like to share what i have learnt,

If you are declaring lazy=true in .hbm file like below,

<set name="role2Designation" order-by="ROLE_ID" lazy="true">
<key column="ROLE_ID"/>
<one-to-many class="org.val.system.la.business.service.dto.Role2DesignationDTO"/>
</set>


It means you forced the hibernate to initialize the required object on demand i.e. whenever you required.

For this case the hibernate session should be opened when hibernate initalize the object on demand. Then only hibernate can fetch the data from the DB. If you are declaring lazy="false" then hibernate will never do the lazy initlization though session is opened.

try{
Session session = LASHibernateUtil.currentSession();
roleList = session.createCriteria( RoleVO.class ).createCriteria( "role2Designation" ).add( Restrictions.eq( "designationId", designationId ) ).list();
}
catch ( HibernateException hibernateException ){
throw new LASServiceException( ILASErrorCode.TECHNICAL_PROPLEM );
}
finally{
LASHibernateUtil.closeSession(); // Error Because the Hibernate session is closed here.
}


I got LazyInitalizationException because of the closed session.

how can we avoid LazyInitalizationException?

1. Opening the session always
a. Open hibernate session and close at the end ( using servlet filter )
b. Open hibernate session using ThreadLocal ( I preferred this method )


2. Load all required data in business layer and pass the values to presentation layer using Hibernate.initialize()

Here is the code for Hibernate.initialize()

while ( it.hasNext() ){
Role2DesignationDTO role2Desi = ( Role2DesignationDTO ) it.next();
Hibernate.initialize( role2Desi );
}

I have initalized the required objects in business layer itself and it will automatically passed it to the presenation layer because of relationships. Keep in mind that this initalization is done before closing the session.

By this above two methods we can avoid this LazyInitalizationException. Hope it is useful to know the basic ideas.

Here is the code for opening a session using ThreadLocal

public class LASHibernateUtil {
private static final SessionFactory sessionFactory;
static{
try{
sessionFactory = new Configuration().configure().buildSessionFactory();
}
catch ( HibernateException hibernateException ){
throw new RuntimeException( "Exception occurs while Building SessionFactory" + hibernateException.getMessage(), hibernateException );
}
}

public static final ThreadLocal session = new ThreadLocal();

public static Session currentSession() throws HibernateException {
Session s = ( Session ) session.get();
if ( s == null ){
s = sessionFactory.openSession();
}
session.set( s );
return s;
}

public static void closeSession() throws HibernateException {
Session s = ( Session ) session.get();
session.set( null );
if ( s != null ){
s.close();
}
}
}