控制休眠会话(何时手动关闭)

时间:2010-10-28 07:39:55

标签: hibernate session

我是hibernate的新手,在阅读了hibernate api和教程之后,看来会话应该在不使用时关闭。

像这样:

Session sess=getSession();
Transcration tx=sess.beginTranscration();
//do something using teh session
sess.save(obj);
tx.commit();
sess.close;

我在毫无疑问的应用程序中使用它时毫无疑问。 但是我不确定何时在网络应用中使用。

例如,我有一个servlet:TestServlet从客户端接收参数,然后我调用Manager来根据参数查询内容,就像这样:

class TestServlet{
  doGet(HttpServletRequset,httpServletResponse){
    String para1=request.getParam...();
    String para2=.....
    new Manager().query(para1,para2);
  }
}

class Manager{
  public String query(String pa1,String pa2){
    Session=....// get the session
    //do query using para1 and 1
    session.close() //Here, I wonder if I should close it.
  }
}

我应该在查询方法中关闭会话吗?

因为有人告诉我,hibernate中的会话就像jdbc中的连接一样。那么频繁打开和关闭它是正确的方法吗?

BTW,每次都需要tx.commit()吗?

还有什么是在servlet中使用session的线程问题,因为我看到会话在api中不是线程安全的。

4 个答案:

答案 0 :(得分:111)

  

我是hibernate的新手,在阅读了hibernate api和教程之后,似乎会话在不使用时应该是cloesd。

完成后应该关闭(但我们会看到,这可以自动完成)。

  

在独立应用程序中使用它时我毫无疑问。但是我不确定何时在网络应用中使用。

嗯,正如文档11.1.1. Unit of work部分所述,多用户客户端/服务器应用程序中的最常见模式是 session-per-请求

  

例如,我有一个servlet:TestServlet从客户端接收参数,然后我调用Manager来根据参数查询:就像这样(...)我应该在查询方法中关闭会话?

这完全取决于你如何获得会话。

  • 如果您使用sessionFactory.getCurrentSession(),您将获得一个绑定到事务生命周期的“当前会话”,并在事务结束(提交或回滚)时自动刷新和关闭。
  • 如果您决定使用sessionFactory.openSession(),则必须自行管理会话并“手动”刷新并关闭它。

要实现每个请求的会话模式,请选择第一种方法(更简单,更简洁)。使用第二种方法实现long conversations

维基页面Sessions and transactions是对此主题文档的很好补充。

  

BTW,每次都需要tx.commit()吗?

您可能希望阅读Non-transactional data access and the auto-commit mode以澄清一些事情,但简单来说,您的Hibernate代码必须在事务中执行,我建议使用显式事务边界(即显式{{ 1}}和beginTransaction)。

  

还有什么是在servlet中使用session的线程问题,因为我看到会话在api中不是线程安全的。

只是不要使它成为Servlet的实例变量,你就不会有任何问题。

参考

答案 1 :(得分:0)

如果您通过sessionFactory.openSession()进行会话,则必须从外部关闭。非预期的打开会话可能导致数据泄露。此外,它还可以邀请Web App安全威胁。

答案 2 :(得分:0)

我们可以使用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

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

答案 3 :(得分:0)

每当第一次调用getCurrentSession()时,一个会话就会打开,而在事务结束时,会话会关闭。

如果一个会话不存在,则创建一个全新的会话;如果一个会话已经存在,则使用一个现有的会话。它使用自动刷新和自动关闭属性自动配置为true,表示Session将被自动刷新和关闭。

如果您使用的是getCurrentSession(),那么如果要尝试使用此方法,则无需关闭连接,那么您将面临异常。