在我的应用程序中打开的位置和关闭SessionFactory的位置

时间:2015-05-07 09:00:24

标签: java hibernate session

我正在开发jsf应用程序并使用hibernate作为后端。我想创建会话工厂并通过应用程序关闭它一次。我正在用util类创建Session工厂。

import org.hibernate.HibernateException;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import org.hibernate.service.ServiceRegistry;
import org.hibernate.service.ServiceRegistryBuilder;

public class HibernateUtil
{
private static SessionFactory sessionFactory;
private static ServiceRegistry serviceRegistry;

static
{
    try
    {
        Configuration configuration = new Configuration().configure();

        serviceRegistry = new ServiceRegistryBuilder().applySettings(configuration.getProperties()).buildServiceRegistry();
        sessionFactory = configuration.buildSessionFactory(serviceRegistry);
    }
    catch (HibernateException he)
    {
        System.err.println("Error creating Session: " + he);
        throw new ExceptionInInitializerError(he);
    }
}

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

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

在我的每个DAO类方法中,我打开会话工厂并关闭它。所以我只能打开/关闭会话工厂一次申请。 提前谢谢。

6 个答案:

答案 0 :(得分:8)

规则是在整个应用程序中应该只有一个SessionFactory。

打开和关闭它的位置取决于应用程序:

  • 对于经典应用程序,它将在main中打开和关闭。
  • 对于Web应用程序,它将在ServletContextListener中打开和关闭(分别在contextInitialized和contextDestroyed事件中)

您也可以使用单例并以静态方法创建它,并像上面一样将其关闭。

但请不要在DAO方法结束时关闭会话工厂

对于Sessions,您在一个工作单元的开头到openSession获得一个,并在提交或回滚后关闭它(如果出现异常,您必须回滚并立即关闭会话)。但是Hibernate手册指出: Hibernate org.hibernate.Session的范围很灵活,但是你永远不应该设计你的应用程序来为每个数据库操作使用新的Hibernate org.hibernate.Session。即使在以下示例中使用它,也要考虑每个操作的会话是反模式。

通常,您将根据需要的事务使用一个会话。例如,在Web应用程序中,每个请求的会话是一种常见的设计。

但您也可以使用像Spring这样的更高级别的框架,它将为您完成所有SessionFactory和Session管理。

答案 1 :(得分:4)

SessionFactory: SessionFactory的工作是处理应用程序中的所有会话。通常,应用程序中只有 只有一个sessionFactory ,允许创建执行CRUD操作所需的会话次数

SessionFactory是不可变的&线程安全。因此,多个线程可以访问同一个sessionFactory对象。

static {
    try {
        Configuration configuration = new Configuration().configure("hibernate.cfg.xml");
        serviceRegistry = new StandardServiceRegistryBuilder().applySettings(
                configuration.getProperties()).build();
        sessionFactory = auditConfiguration.buildSessionFactory(serviceRegistry);
    } catch (Throwable ex) {
        System.err.println("Initial SessionFactory creation failed." + ex);
        throw new ExceptionInInitializerError(ex);
    }
}

Session: 会话是 轻量级和非线程安全的 对象。因此,不能在多个线程之间共享会话。应该为DB 上的每个事务创建创建,读取,更新或删除&交易完成后必须关闭。

try {
    Session session = sessionFactory.openSession();
    // do some CRUD operation
} catch(Exception ex) {
    // On error, revert all changes done
    if (transaction != null) {
        transaction.rollback();
    }
} finally {
    if (session != null) {
        session.close();
    }
}

所以我建议你打开/关闭session而不是sessionFactory

答案 2 :(得分:1)

最好的方法是使用ThreadLocal

public class MyUtil {
private static SessionFactory sessionFactory;
private static ServiceRegistry serviceRegistry;
private static final ThreadLocal<Session> threadLocal;

static {
    try {
        Configuration configuration = new Configuration();
        configuration.configure();
        serviceRegistry = new StandardServiceRegistryBuilder().applySettings(configuration.getProperties()).build();
        sessionFactory = configuration.buildSessionFactory(serviceRegistry);
        threadLocal = new ThreadLocal<Session>();

    } catch(Throwable t){
        t.printStackTrace();
        throw new ExceptionInInitializerError(t);
    }
}
public static Session getSession() {
    Session session = threadLocal.get();
    if(session == null){
        session = sessionFactory.openSession();
        threadLocal.set(session);
    }
    return session;
}

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

public static void closeSessionFactory() {
    sessionFactory.close();
    StandardServiceRegistryBuilder.destroy(serviceRegistry);
  }
}

此处,SessionFactory仅使用static块初始化一次。 因此,只要main类调用getSession(),就会首先在threadLocal对象中检查是否存在Session对象。 因此,该程序提供了线程安全性。 每次操作后,closeSession()将关闭会话并将threadLocal对象设置为null。 最后拨打closeSessionFactory()

答案 3 :(得分:0)

  

所以我只能打开/关闭会话工厂一次   应用

会话工厂每个应用程序仅实例化一次&amp;应用程序关闭时会被破坏。会话工厂是会话工厂,因此它只设置一次。

关于会话,你应该打开&amp;在每种方法中关闭一个会话。你不应该有太多的公开会话。

因此必须在事务结束后关闭会话。

如果您不关闭Hibernate会话,因此在每次事务后都不释放JDBC连接,那么通常称为连接泄漏。因此,在多个请求(取决于连接池的大小)之后,服务器将无法获取连接以响应您的请求。实际上,服务器将等待连接被释放并再次在池中可用,它似乎会挂起。

答案 4 :(得分:0)

它不足以关闭会话。您必须另外关闭工厂。

session.close();
session.getSessionFactory().close();

答案 5 :(得分:-2)

在我的应用程序中打开的位置和关闭SessionFactory的位置

您正在使用单身会话工厂对象。因此,您可以使用类名调用getSessionFactory()方法。因此,您每次都需要为会话工厂创建对象。

你的DAO类方法应该是这样的

DAO课程中的方法

public boolean createUser(NewUserDTO newUserDTO) {
    try {
        sessionFactory = DBUtils.getSessionFactory();
        session = sessionFactory.openSession();
        transaction = session.beginTransaction();
        session.save(newUserDTO);
        session.getTransaction().commit();
    } catch (RuntimeException runtimeException) {
        LOGGER.error(runtimeException);
        transaction.rollback();
        return false;
    } finally {
        if (session != null) {
            session.close();
        }
    }
    return true;
}

必须为每个方法关闭会话。这样你就不会为每个类创建会话工厂。