【问题标题】:Control the hibernate session(when to close it manually)控制休眠会话(何时手动关闭)
【发布时间】:2011-05-01 17:51:29
【问题描述】:

我是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中的连接。那么如此频繁地打开和关闭它是正确的方法吗?

顺便说一句,每次都需要 tx.commit() 吗?

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

【问题讨论】:

    标签: hibernate session


    【解决方案1】:

    我是hibernate新手,看了hibernate api和教程后,似乎会话在不使用时应该关闭。

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

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

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

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

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

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

    要实现 session-per-request 模式,请首选第一种方法(更简单且不那么冗长)。使用第二种方法来实现long conversations

    wiki 页面Sessions and transactions 是对有关该主题的文档的一个很好的补充。

    顺便说一句,每次都需要 tx.commit() 吗?

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

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

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

    参考文献

    【讨论】:

    • 感谢您的回复。现在我决定创建一个静态类 HibernateUtil,它可以通过 getCurrentSession() 返回会话,然后我调用 HibernateUtil 在其他地方获取会话。对吗?
    • 另外,每个请求每个会话,我想知道这是否会导致性能下降,因为当我不使用休眠时,我将使用连接池。
    • @hguser:如果您不使用 EJB 或 Spring,那么可以,选择 HibernateUtils 类。不,获取 Session 不是一项昂贵的操作,也不是性能问题,它并不比从池中获取连接更糟糕。
    • 谢谢 :) 一个相关问题:我应该如何了解 jdbc 和 sql 才能更好地使用和学习 hibernate?
    • 所以,getCurrentSession() 将被“会话上下文”实现自动关闭。
    【解决方案2】:

    如果您通过sessionFactory.openSession() 获取会话,那么您必须在外部关闭它。意外打开会话可能会导致数据泄漏。此外,它还可以向 Web App 安全威胁发出邀请。

    【讨论】:

      【解决方案3】:

      我们可以使用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 只使用静态块初始化一次。因此,每当main 类调用getSession() 时,首先在threadLocal 对象中检查Session 对象的存在。 因此,该程序提供线程安全。 每次操作后,closeSession() 将关闭会话并将threadLocal 对象设置为空。 最后拨打closeSessionFactory()

      【讨论】:

        【解决方案4】:

        第一次调用getCurrentSession() 时会打开会话,并在事务结束时关闭会话。

        如果一个会话不存在,则创建一个全新的会话,如果一个会话已存在,则使用现有会话。它自动将 auto-flush 和 auto-close 属性配置为 true 意味着 Session 将自动刷新和关闭。

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2012-03-10
          • 1970-01-01
          • 2011-01-23
          • 1970-01-01
          • 2013-12-19
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多