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

我正在开发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类方法中,我打开会话工厂并关闭它。 所以我只能打开/关闭会话工厂一次申请。 提前致谢。

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

您正在使用singleton sessiong facoty对象。 所以你可以用类名调用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; } 

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

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

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

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

您也可以使用单例并以静态方法创建它,并像上面那样在结尾处关闭它。

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

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

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

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

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); } } 

会话:会话是一个轻量级和非线程安全的对象。 因此,不能在多个线程之间共享会话。 它应该为DB上的每个事务创建,包括Create,Read,Update或Delete,并且必须在事务完成时关闭。

 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

最好的方法是使用ThreadLocal

 public class MyUtil { private static SessionFactory sessionFactory; private static ServiceRegistry serviceRegistry; private static final ThreadLocal threadLocal; static { try { Configuration configuration = new Configuration(); configuration.configure(); serviceRegistry = new StandardServiceRegistryBuilder().applySettings(configuration.getProperties()).build(); sessionFactory = configuration.buildSessionFactory(serviceRegistry); threadLocal = new ThreadLocal(); } 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()

所以我只能打开/关闭会话工厂一次申请。

会话工厂仅在每个应用程序中实例化一次,并在应用程序关闭时被销毁。 会话工厂是会话工厂,因此它只设置一次。

关于会话,您应该在每种方法中打开和关闭会话。 你不应该有太多的开放会话。

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

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

它不足以结束会议。 你必须另外关闭工厂。

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