在我的应用程序中打开的位置和关闭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();
- 具有共享主键的两个表之间的OneToOne
- 为多个模式中的实体生成Liquibase-hibernate changelog
- 启动时出现Hibernateexception
- 如何使用hibernate在spring boot中实现分页
- 如何根据用户的选择动态生成SQL查询?
- 为什么即使在Spring服务类的第二种方法中传播= Propagation.REQUIRES_NEW时,事务也会回滚?
- 在Hibernate 3.2中使用连接池(c3p0-0.9.1.2)时,获取exception和应用程序无法与MySqL数据库连接?
- 如何创建支持通用ID的通用实体模型类,包括自动生成的ID?
- Hibernate,MySQL Views和hibernate.hbm2ddl.auto = validate