2017-02-15 12 views
0

Hibernateで「1セッションあたりのHTTPリクエスト」パターンを実装しようとしていて、1回目のリクエストで機能します:サーブレットのdoGetいくつかのものを取得し、セッションを閉じます。シングルトンのDAOインスタンスは、HTTPトランザクション間で古いクローズドセッションを維持します

しかし、ブラウザを更新すると、My DAO Singletonインスタンス(そのコンストラクタがSessionFactoryからセッションを取得します)が2回目に呼び出されますが、古いセッションオブジェクト(シングルトンコンストラクタはまだ呼び出されません)が使用されます。私は "セッションが閉じている"エラーを取得します。

シングルトンのインスタンスを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(); 
     } 
    } 
} 

古典スレッド-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コードは、トランザクションが宣言的に処理しなければならない、とサービス層ではなく、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

サービスレイヤーは私が必要としていた手がかりで、なぜモデルがトランザクションとセッションを管理しなければならないのかわかりませんでした。 私はあなたの役に立つ指示を(ブラウジングの少し後に)正確に得ると、サーブレットとDAOメソッド間の中間層として働き、トランザクション、エラー、返されたオブジェクトの扱いといった二次懸念を管理します。 将来の読者の皆様には、大きな写真を手に入れるためのこのリンクを提案してください: https://msdn.microsoft.com/en-us/library/ee658090.aspx – Yow

関連する問題