2017-02-15 30 views
0

我试图用Hibernate实现“每会话一次请求”模式,并且它适用于第一个请求:servlet的doGet()方法打开会议,获取一些东西,并关闭会议。Singleton DAO实例在HTTP事务之间保持旧的关闭会话

但是,当我刷新浏览器时,我的DAO Singleton实例(其构造函数从SessionFactory获取会话)被第二次调用,但仍使用旧的会话对象(不再调用单例构造函数)。然后我得到一个“Session is closed”错误。我想,单身实例必须保存在HTTP请求之间的缓存中,所以:我怎样才能获得再次调用的DAO单例构造函数? (或其他优雅的解决方案有新鲜的SessionFactory会话对象?)

非常感谢您

该servlet:

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 
    try { 
     // Gets the session, eventually creates one 
     Session s = HibernateUtil.currentSession(); 

     // Gets data from singleton DAO instance 
     MySingletonDAO o = MySingletonDAO.getInstance(); 
     List<Stuff> stuff = o.getAllTheStuff(); 

     // send it to the view 
     request.setAttribute("foo",stuff); 
     RequestDispatcher dispatcher = getServletContext().getRequestDispatcher(vue); 
     dispatcher.forward(request, response); 

    } 
      /* error handling blah blah */ 
    finally { 
     // closing the session 
     HibernateUtil.closeSession(); 
    } 

MySingletonDAO.java:

public class MySingletonDAO { 
    // Usual singleton syntax 
    private static MySingletonDAO INSTANCE = new MySingletonDAO(); 
    public static MySingletonDAO getInstance() { return INSTANCE;} 

    private Session session; 

    private MySingletonDAO() { 
     session = HibernateUtil.currentSession(); 
     System.out.println("This constructor is called only on the first HTTP transaction"); 
    } 

    public List<Stuff> getAllTheStuff() { 
     try { 
      session.beginTransaction(); 
      Query q = session.createQuery("FROM StuffDBTable"); 
      session.getTransaction().commit(); 
      return (List<Stuff>) q.list(); 
     } 
    } 
} 

一个经典螺纹-safe HibernateUtil.java:

public class HibernateUtil { 

    private static final SessionFactory sessionFactory; 
    public static final ThreadLocal session = new ThreadLocal(); 

    static { 
     try { 
      // Creates the SessionFactory 
      sessionFactory = new Configuration().configure().buildSessionFactory(); 
     } catch (HibernateException he) { 
      throw new RuntimeException("Conf problem : "+ he.getMessage(), he); 
     } 
    } 


    public static Session currentSession() throws HibernateException { 
     Session s = (Session) session.get(); 
     // Opens a new Session, if this Thread has none 
     if (s == null || !s.isOpen()) { 
      s = sessionFactory.openSession(); 
      session.set(s); 
     } 
     return s; 
    } 

    public static void closeSession() throws HibernateException { 
     Session s = (Session) session.get(); 
     session.set(null); 
     if (s != null) 
      s.close(); 
    } 
} 

回答

1

你所要求的是没有意义的:如果在每个请求中调用单例的构造函数,它就不再是单例。该会话确实在请求结束时关闭,但DAO保留对会话的引用,而不是在每次调用时从您的util类中获取它。

你的DAO代码应该

public class MySingletonDAO { 
    private static MySingletonDAO INSTANCE = new MySingletonDAO(); 
    public static MySingletonDAO getInstance() { return INSTANCE;} 

    private MySingletonDAO() { 
    } 

    public List<Stuff> getAllTheStuff() { 
     Session session = HibernateUtil.currentSession(); 
     try { 
      session.beginTransaction(); 
      Query q = session.createQuery("FROM StuffDBTable"); 
      session.getTransaction().commit(); 
      return (List<Stuff>) q.list(); 
     } 
    } 
} 

尽管如此,交易应当声明处理,并且应该在服务层而非DAO层处理:交易通常使用deveral的DAO,该实体由归国DAO应该保持管理,并且对这些实体所做的所有访问和修改都应在交易中进行。

我强烈建议使用Java EE容器或Spring来为您处理事务和会话处理。您还应该使用标准的JPA API而不是专有的Hibernate API。

+0

服务层是我需要的线索,我看不出为什么模型必须管理事务和会话。 如果我正确地(在浏览了一段时间后)得到有用的指导,它将作为Servlet和DAO方法之间的中介层,来管理事务,错误和返回对象处理等次要问题。 如果我可以,为了将来的读者,建议这个链接帮助我获得大局: https://msdn.microsoft.com/zh-cn/library/ee658090.aspx – Yow

相关问题