我正在开发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类方法中,我打开会话工厂并关闭它。所以我只能打开/关闭会话工厂一次申请。 提前谢谢。
答案 0 :(得分:8)
规则是在整个应用程序中应该只有一个SessionFactory。
打开和关闭它的位置取决于应用程序:
您也可以使用单例并以静态方法创建它,并像上面一样将其关闭。
但请不要在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;
}
必须为每个方法关闭会话。这样你就不会为每个类创建会话工厂。