Должны ли сессия и фабрика быть закрыты?

Я использую Hibernate 5.0.2.Final с подключением к источнику данных (на Tomcat 8.0.15) и начал спрашивать себя, нужно ли закрывать не только сеанс, но и SessionFactory?

Прямо сейчас это выглядит так:

public static List<HibernateList> getHibernateList() {
        Session session = null;
        final String hql = "SELECT H FROM myhibernate.MyHibernate";
        try {
            SessionFactory factory = HibernateUtil.getSessionFactory();
            session = factory.openSession();
            session.beginTransaction();

            Query query = session.createQuery(hql);

            return query.list();
        } catch (HibernateException hibex) {
            Logger.getLogger(Hibernatepicker.class.getName()).log(Level.INFO, null, hql);
            Logger.getLogger(Hibernatepicker.class.getName()).log(Level.SEVERE, null, hibex);
        } finally {
            try {
                if (session != null) {
                    session.close();
                }
            } catch (HibernateException hibex) {
            }//Nothing I could do...
        }
        return null;
    }

Некоторые подробности из hibernate.cfg.xml

<property name="hibernate.connection.datasource">java:comp/env/jdbc/sqlserv</property>        
<property name="current_session_context_class">thread</property> 
<property name="cache.provider_class">org.hibernate.cache.NoCacheProvider</property> 
<property name="hbm2ddl.auto">auto</property> 
<property name="show_sql">false</property>       
<property name="hibernate.generate_statistics">true</property>  

И HibernateUtil:

public class HibernateUtil {
private static final SessionFactory sessionFactory;

static {
    try {
        Configuration cfg = new Configuration();
        sessionFactory = cfg.configure("hibernate.cfg.xml").buildSessionFactory();
    } catch (Throwable ex) {
        Logger.getLogger(HibernateUtil.class.getName()).log(Level.SEVERE, null, ex);
        throw new ExceptionInInitializerError(ex);
    }
}

public static SessionFactory getSessionFactory() {
    return sessionFactory;
}
}

Я не решил, нужно ли вызывать этот метод в блоке finally вместо того, чтобы просто закрывать сеанс:

public static void disconnect(Session session, SessionFactory factory) {
        try {
            if (session != null) {
                session.close();
            } else {
                Logger.getLogger(HibernateUtil.class.getName()).log(Level.INFO, null, "Session is Null");
        }

    } catch (HibernateException | NullPointerException hibex) {
        Logger.getLogger(HibernateUtil.class.getName()).log(Level.INFO, null, "Couldn't close session, but there's nothing we can do...");
        Logger.getLogger(HibernateUtil.class.getName()).log(Level.SEVERE, null, hibex);
    }
    try {
        if (factory != null) {
            factory.close();
        } else {
            Logger.getLogger(HibernateUtil.class.getName()).log(Level.INFO, null, "Factory is Null");
        }

    } catch (HibernateException | NullPointerException hibex) {
        Logger.getLogger(HibernateUtil.class.getName()).log(Level.INFO, null, "Couldn't close session, but there's nothing we can do...");
        Logger.getLogger(HibernateUtil.class.getName()).log(Level.SEVERE, null, hibex);
    }
}

person Qohelet    schedule 20.10.2015    source источник


Ответы (1)


Вы не должны не закрывать свой SessionFactory при каждом запросе. Ваш SessionFactory должен быть инициализирован только один раз для каждого приложения.

Из документации по гибернации.

Основным контрактом здесь является создание экземпляров Session. Обычно приложение имеет один экземпляр SessionFactory, и потоки, обслуживающие клиентские запросы, получают экземпляры Session из этой фабрики. Внутреннее состояние SessionFactory неизменно. После его создания это внутреннее состояние устанавливается. Это внутреннее состояние включает в себя все метаданные об объектно-реляционном сопоставлении.

Разработчики должны быть потокобезопасными.

person bhdrkn    schedule 20.10.2015
comment
Отлично, спасибо за быстрый ответ. Есть ли способ убедиться, что он инициализирован ровно один раз? - person Qohelet; 20.10.2015
comment
@Qohelet Да, есть. Вы можете использовать шаблон Singleton для обеспечения одиночной инициализации или, если вы используете любую среду CDI (например, Spring и т. д.), они поддерживают встроенную функциональность такого типа. - person bhdrkn; 20.10.2015
comment
мой HibernateUtil выглядит как Singelton-ish ...? Правильно ли мое предположение, что это сделано правильно? - person Qohelet; 20.10.2015