首页 文章

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

提问于
浏览
61

我是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的线程问题,因为我看到会话在api中不是线程安全的 .

3 回答

  • 0

    如果您正在通过 sessionFactory.openSession() 进行会话,那么您必须 close it externally . 非预期的打开会话可能导致数据泄露 . 此外,它还可以邀请Web App安全威胁 .

  • 110

    我们可以利用 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 对象设置为null . 最后拨打 closeSessionFactory() .

  • 0

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

    它应该在你完成后关闭(但这可以自动完成,我们将看到) .

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

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

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

    这一切都取决于你如何获得会话 .

    • 如果使用 sessionFactory.getCurrentSession() ,您将获得绑定到事务生命周期的"current session",并在事务结束(提交或回滚)时自动刷新和关闭 .

    • 如果你决定使用 sessionFactory.openSession() ,你必须自己管理会话并刷新并关闭它"manually" .

    要实现每个请求的会话模式,首选方法(更容易,更简洁) . 使用第二种方法实现long conversations .

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

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

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

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

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

    参考文献

相关问题