Hibernate opening/closing session, the correct approach for DAO

HeavenAgain picture HeavenAgain · Jan 12, 2012 · Viewed 14.6k times · Source

I have written this Hibernate object DAO, however with this approach, it is using session per update approach (which I don't think it's right).

The reason why I don't think its right because I am running into problems with my User class, which contains collections that are lazily fetched. Since when retrieving each User from the DAO, the session is closed. Therefore I cannot get my collections.

From time to time, it is also doing a lot of unnecessary updates to the table because the object is detached.

So are there any ways of fixing my DAO, like using getCurrentSession()?

import java.util.List;

import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.Transaction;

import org.test.util.DataAccessLayerException;
import org.test.util.HibernateUtil;

public abstract class AbstractDao {
    protected Session session;
    protected Transaction tx;
    public AbstractDao() {
        HibernateUtil.buildIfNeeded();
    }
    protected void saveOrUpdate(Object obj) {
        try {
            startOperation();
            session.saveOrUpdate(obj);
            tx.commit();
        } catch (HibernateException e) {
            handleException(e);
        } finally {
            HibernateUtil.close(session);
        }
    }
    protected void delete(Object obj) {
        try {
            startOperation();
            session.delete(obj);
            tx.commit();
        } catch (HibernateException e) {
            handleException(e);
        } finally {
            HibernateUtil.close(session);
        }
    }
    protected Object find(Class clazz, Long id) {
        Object obj = null;
        try {
            startOperation();
            obj = session.load(clazz, id);
            tx.commit();
        } catch (HibernateException e) {
            handleException(e);
        } finally {
            HibernateUtil.close(session);
        }
        return obj;
    }
    protected List findAll(Class clazz) {
        List objects = null;
        try {
            startOperation();
            Query query = session.createQuery("from " + clazz.getName());
            objects = query.list();
            tx.commit();
        } catch (HibernateException e) {
            handleException(e);
        } finally {
            HibernateUtil.close(session);
        }
        return objects;
    }
    protected void handleException(HibernateException e) throws DataAccessLayerException {
        HibernateUtil.rollback(tx);
        throw new DataAccessLayerException(e);
    }
    protected void startOperation() throws HibernateException {
        session = HibernateUtil.openSession();
        tx = session.beginTransaction();
    }
}

HibernateUtil

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;

public class HibernateUtil {

    private static Log log = LogFactory.getLog(HibernateUtil.class);
    private static SessionFactory sessionFactory;

    private static SessionFactory configureSessionFactory()
            throws HibernateException {
        Configuration configuration = new Configuration();
        configuration.configure();
        sessionFactory = configuration.buildSessionFactory();
        return sessionFactory;
    }

    public static SessionFactory buildIfNeeded()
            throws DataAccessLayerException {
        if (sessionFactory != null) {
            return sessionFactory;
        }
        try {
            return configureSessionFactory();
        } catch (HibernateException e) {
            throw new DataAccessLayerException(e);
        }
    }

    public static SessionFactory buildSessionFactory()
            throws HibernateException {
        if (sessionFactory != null) {
            closeFactory();
        }
        return configureSessionFactory();
    }

    public static SessionFactory getSessionFactory() {
        return sessionFactory;
    }

    public static Session openSession() throws HibernateException {
        buildIfNeeded();
        return sessionFactory.openSession();
    }

    public static void closeFactory() {
        if (sessionFactory != null) {
            try {
                sessionFactory.close();
            } catch (HibernateException ignored) {
                log.error("Couldn't close SessionFactory", ignored);
            }
        }
    }

    public static void close(Session session) {
        if (session != null) {
            try {
                session.close();
            } catch (HibernateException ignored) {
                log.error("Couldn't close Session", ignored);
            }
        }
    }

    public static void rollback(Transaction tx) {
        try {
            if (tx != null) {
                tx.rollback();
            }
        } catch (HibernateException ignored) {
            log.error("Couldn't rollback Transaction", ignored);
        }
    }
}

Answer

aleks.n.fedorov picture aleks.n.fedorov · May 30, 2014

Good approach is to add close method to your DAO(AbstractDao) and call it the end of your "unit of work".

And, please, no static references to session, session is not thread safe


Here is a brilliant explanation with sample: Link