Monday, May 22, 2006

proper implementation of lazy-loading in hibernate

traditionally, a database session is closed before the view is rendered. in Hibernate, this may result to a NullPointerException when you enable the framework's lazy-loading facility. lazy-loading enabled association attributes need a live session to be dynamically populated. in the case of web applications, a servlet filter can be used to close the session after the views have been processed and before the response is sent to the client. if there is a transaction, commit and rollback demarcation can be also added. however, starting a new session and transaction can be done in the action or anywhere in the application. below is a utility class that can maintain only one session and one transaction thoughout a single "request to response" process.




import net.sf.hibernate.HibernateException;
import net.sf.hibernate.Session;
import net.sf.hibernate.SessionFactory;
import net.sf.hibernate.Transaction;
import net.sf.hibernate.cfg.Configuration;
import org.apache.log4j.Logger;
import sincang.SystemException;

public class HibernateManager
{
private static final Logger logger = Logger.getLogger(HibernateManager.class);
private static final ThreadLocal threadSession = new ThreadLocal();
private static final ThreadLocal threadTransaction = new ThreadLocal();
private static final SessionFactory sessionFactory;

static
{
try
{
sessionFactory = new Configuration().configure().buildSessionFactory();
}
catch (Throwable e)
{
logger.fatal(e);
throw new ExceptionInInitializerError(e);
}
}

public static Session getSession() throws SystemException
{
Session session = (Session) threadSession.get();
try
{
if (session == null)
{
session = sessionFactory.openSession();
threadSession.set(session);
}
}
catch (HibernateException e)
{
logger.fatal(e);
throw new SystemException(e);
}
return session;
}

public static void closeSession() throws SystemException
{
try
{
Session session = (Session) threadSession.get();
threadSession.set(null);
if ((session != null) && session.isOpen())
{
session.close();
}
}
catch (HibernateException e)
{
logger.fatal(e);
throw new SystemException(e);
}
}

public static void beginTransaction() throws SystemException
{
Transaction transaction = (Transaction) threadTransaction.get();
try
{
if (transaction == null)
{
transaction = getSession().beginTransaction();
threadTransaction.set(transaction);
}
}
catch (HibernateException e)
{
logger.fatal(e);
throw new SystemException(e);
}
}

public static void commitTransaction() throws SystemException
{
Transaction transaction = (Transaction) threadTransaction.get();
try
{
if ((transaction != null) && !transaction.wasCommitted() && !transaction.wasRolledBack())
{
transaction.commit();
threadTransaction.set(null);
}
}
catch (HibernateException e)
{
rollbackTransaction();
logger.fatal(e);
throw new SystemException(e);
}
}

public static void rollbackTransaction() throws SystemException
{
Transaction transaction = (Transaction) threadTransaction.get();
try
{
threadTransaction.set(null);
if ((transaction != null) && !transaction.wasCommitted() && !transaction.wasRolledBack())
{
transaction.rollback();
}
}
catch (HibernateException e)
{
logger.fatal(e);
throw new SystemException(e);
}
finally
{
closeSession();
}
}
}


No comments: