0

I have created a DAO like this: This is based from: Hibernate: CRUD Generic DAO

public class Dao{
    SessionFactory sessionFactory;
    // initialise session factory
    public User save(User o){
        return (User) sessionFactory.getCurrentSession().save(o);
    }

    public User get(Long id){
        return (User) sessionFactory.getCurrentSession().get(User.class, id);
    }

    public User void saveOrUpdate(User o){
                    sessionFactory.getCurrentSession().saveOrUpdate(o);
    }

Now, this is all fine, if my sessionFactory is in the DAO or in other classes. But my problem is calling SessionFactory from the servletContextListener: Here is my code in the listener:

public void contextInitialized(ServletContextEvent event)  {
    StandardServiceRegistry registry = new StandardServiceRegistryBuilder().configure().build();
    try {
        sessionFactory = new MetadataSources(registry).buildMetadata().buildSessionFactory();
        event.getServletContext().setAttribute("factory", sessionFactory);
    } catch(Exception e) {
        e.printStackTrace();
        StandardServiceRegistryBuilder.destroy( registry );
    }
}

How would I call SessionFactory from the DAO in this case aside from actually wrapping a servletRequest inside the DAO?

Community
  • 1
  • 1
lightning_missile
  • 2,821
  • 5
  • 30
  • 58
  • Why are you storing your Hibernate `SessionFactory` inside your `ServletContext`? The whole idea about separation of concern is that you don't want your MVC application layer having to know **how** to access your data, i.e., it should **never** worry about the data/persistence layer **at all**. What you are doing makes your DAO totally dependent on your web layer, which is not recommenced at all. – Buhake Sindi Sep 25 '15 at 08:57
  • It looks like a XY problem. You certainly do not want to put the SessionFactory in the ServletContext and have the DAO get it from there. You should give some context on the general design of your application. – Serge Ballesta Sep 25 '15 at 09:27
  • @Buhake Sindi "Why are you storing your Hibernate SessionFactory inside your ServletContext?" - I want it to be initialised during application startup. I can't think of any other way of making it happen. – lightning_missile Sep 25 '15 at 10:15
  • @Serge Ballesta - it's just some CRUD with few utility methods. – lightning_missile Sep 25 '15 at 10:16
  • I would rather that the DAO works with `Session` instead. If the DAO has no session, then obtain it from `SessionFactory` since 'sessionFactory' is a thread-safe object built once per application lifetime. You won't need to worry about it. Alternatively, create a singleton `HibernateUtils` class which returns you a `SessionFactory` instead. – Buhake Sindi Sep 25 '15 at 10:28

1 Answers1

1

I strongly discourage storing Hibernate SessionFactory into Servlet's ServletContext. Also, have your DAO use your Hibernate Session instead.

To tackle your issue of having your Hibernate SessionFactory instantiated once, I created a singleton class to manage this:

/**
 * 
 */
package za.co.sindi.persistence.util;

import java.util.logging.Level;
import java.util.logging.Logger;

import org.hibernate.HibernateException;
import org.hibernate.Interceptor;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.cfg.Configuration;
import org.hibernate.service.ServiceRegistry;

/**
 * This is a Hibernate utility class that strictly uses the Hibernate 4.x library.
 * 
 * @author Buhake Sindi
 * @since 26 November 2012
 *
 */
public final class HibernateUtils {

    private static final Logger logger = Logger.getLogger(HibernateUtils.class.getName());
    private static Configuration configuration;
    private static SessionFactory sessionFactory;
    private static ServiceRegistry serviceRegistry;
    private static final ThreadLocal<Session> sessionThread = new ThreadLocal<Session>();
    private static final ThreadLocal<Interceptor> interceptorThread = new ThreadLocal<Interceptor>();

    static {
        try {
            configuration = new Configuration();
            serviceRegistry = new StandardServiceRegistryBuilder().build();
            sessionFactory = configuration.configure().buildSessionFactory(serviceRegistry);
        } catch (HibernateException e) {
            logger.log(Level.SEVERE, "Error intializing SessionFactory.", e.getLocalizedMessage());
            throw new ExceptionInInitializerError(e);
        }
    }

    /**
     * Private constructor
     */
    private HibernateUtils() {}

    /**
     * @return the sessionFactory
     */
    public static SessionFactory getSessionFactory() {
        return sessionFactory;
    }

    /**
     * Retrieves the current session local to the thread.
     * 
     * @return Hibernate {@link Session} for current thread.
     * @throws HibernateException when Hibernate has a problem opening a new session.
     */
    public static Session getSession() {
        Session session = sessionThread.get();
        if (session == null) {
            Interceptor interceptor = getInterceptor();
            if (interceptor != null) {
                session = getSessionFactory().withOptions().interceptor(interceptor).openSession();
            } else {
                session = getSessionFactory().openSession();
            }

            if (session != null) {
                sessionThread.set(session);
            }
        }

        return session;
    }

    /**
     * Closes the Hibernate Session (created from the <code>getSession()</code> session.
     */
    public static void closeSession() {
        Session session = sessionThread.get();
        sessionThread.set(null);
        if (session != null && session.isOpen()) {
            session.close();
        }
    }

    /**
     * Registers a Hibernate {@link Interceptor}.
     * @param interceptor
     */
    public static void registerInterceptor(Interceptor interceptor) {
        interceptorThread.set(interceptor);
    }

    /**
     * Get the registered Hibernate Interceptor.
     * @return
     */
    public static Interceptor getInterceptor() {
        return interceptorThread.get();
    }
}

And in my DAO, I just retrieve the session as HibernateUtils.getSession();. That way, my MVC application has no reference to my specific DAO implementation.

I hope this helps.

Buhake Sindi
  • 87,898
  • 29
  • 167
  • 228
  • Where should I instantiate this? – lightning_missile Sep 25 '15 at 10:47
  • It's instantiated in the `static` block and instantiated once.. All you have to do is to retrieve the `Session`. No need to worry about re-instantiating the `SessionFactory` again, hence why it's a Singleton class. – Buhake Sindi Sep 25 '15 at 10:48
  • Hello, Can you please explain why you discourage to store the SessionFactory in the ServletContext ? It's seams safer than in static variable. – Orden Mar 02 '16 at 08:58
  • 1
    @Orden because `ServletContext` is your front-end application and you want to separate your concerns, i.e., your presentation layer must never know the intricacies of the of the repository layer. – Buhake Sindi Nov 14 '16 at 12:51