2017-02-15 6 views
0

Hibernate에서 "HTTP 요청 당 1 세션"패턴을 구현하려고하는데 첫 번째 요청에 대해 작동합니다. 서블릿의 doGet() 메소드가 열림 세션, 몇 가지 물건을 가져오고, 세션을 닫습니다.싱글 톤 DAO 인스턴스가 HTTP 트랜잭션 사이에 오래된 닫힌 세션을 유지합니다.

그러나 브라우저를 새로 고치면 My DAO Singleton 인스턴스 (생성자가 SessionFactory에서 세션을 가져옴)가 두 번째 호출되지만 여전히 이전 세션 객체 (싱글 톤 생성자가 다시 호출되지 않음)를 사용합니다. 그런 다음 "세션 닫힘"오류가 발생합니다.

나는 싱글 톤 인스턴스가 HTTP 요청 사이에서 캐시에 보관되어야한다고 생각한다. 다시 호출 된 DAO 싱글 톤 생성자를 어떻게 얻을 수 있습니까? (또는 다른 우아한 해결책은 신선한 SessionFactory에 세션 객체를 가지고하는?)

서블릿 대단히 감사합니다

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(); 
     } 
    } 
} 

고전 스레드 - 안전 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 코드는 트랜잭션이 선언적으로 처리되어야하고, 오히려 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(); 
     } 
    } 
} 

가 있어야한다 : 트랜잭션은 일반적으로 deveral의 DAO를 사용 엔티티에 의해 반환 DAO는 관리 상태를 유지해야하며 이러한 엔터티에 대한 모든 액세스와 수정은 트랜잭션 내부에서 이루어져야합니다.

Java EE 컨테이너 또는 Spring을 사용하여 트랜잭션 및 세션 처리를 처리하는 것이 좋습니다. 독점적 인 Hibernate API가 아닌 표준 JPA API도 사용해야합니다.

+0

서비스 레이어는 내가 필요한 단서이며 왜 모델이 트랜잭션과 세션을 관리해야하는지 알 수 없습니다. 도움이되는 지침 (브라우저를 조금 읽은 후에)이 올바르게 처리되면 Servlet과 DAO 메소드 사이의 중간 계층 역할을하여 트랜잭션, 오류 및 반환 된 객체 처리와 같은 2 차적인 문제를 관리합니다. 향후 독자를 위해 큰 그림을 가져 오는 데 도움이되는 다음 링크를 제안 할 수 있습니다. https://msdn.microsoft.com/en-us/library/ee658090.aspx – Yow