2015-11-06 54 views
1

我有一個jsf項目,當你點擊一個鏈接進入頁面時,運行查詢來填充所述頁面上顯示的列表的方法被調用。在HIbernate的web項目中關閉對方會話的線程

但是,當我在兩個開放標籤,或在同一時間兩個不同的瀏覽器打開鏈接,其中一人似乎是在會議閉幕而其他還在工作,我得到的異常

Servlet.service() for servlet [Faces Servlet] in context with path [/wplexeo] threw exception [Session is closed!] with root cause 

這是代碼。被調用的方法是executeNamedQuery,每次調用時都會打開和關閉會話。我雖然ThreadLocal應該避免這種情況,也許我不應該在此刻關閉會話。

private static ThreadLocal<Session> sessions = new ThreadLocal<Session>(); 
private static ThreadLocal<Transaction> transactions = new ThreadLocal<Transaction>(); 
private static SessionFactory sessionFactory; 

static 
{ 
    HibernateUtil.sessionFactory = new AnnotationConfiguration().configure().buildSessionFactory(); 
} 

public List<? extends Entity> executesNamedQuery(final String query, final Map<String, Object> parameters) 
    throws DaoHibernateException 
{ 
    this.openSessionAndBeginTransaction(); 
    final Query namedQuery = this.session.getNamedQuery(query); 
    if (parameters != null) 
    { 
     for (final String paramName : parameters.keySet()) 
     { 
      namedQuery.setParameter(paramName, parameters.get(paramName)); 
     } 
    } 
    final List<? extends Entity> result = namedQuery.list(); 
    this.commitTransactionAndCloseSession(); 
    return result; 
} 
    private void openSessionAndBeginTransaction() throws DaoHibernateException 
{ 
    this.session = HibernateUtil.openSession(); 
    try 
    { 
     this.transaction = HibernateUtil.beginTransaction(); 
    } 
    catch (final HibernateException e) 
    { 
     System.out.println(e.getCause()); 
     throw new DaoHibernateException(ExceptionType.ABRIR_TRANSACAO, e, null); 
    } 
} 




public static Session openSession() 
{ 
    HibernateUtil.sessions.set(HibernateUtil.sessionFactory.openSession()); 
    return HibernateUtil.sessions.get(); 
} 

public static Transaction beginTransaction() 
{ 
    HibernateUtil.transactions.set(currentSession().beginTransaction()); 
    return HibernateUtil.transactions.get(); 
} 

private void commitTransactionAndCloseSession() throws DaoHibernateException 
{ 
    try 
    { 
     this.transaction.commit(); 
    } 
    catch (final HibernateException e) 
    { 
     throw new DaoHibernateException(ExceptionType.COMITTAR_TRANSACAO, e, null); 
    } 
    finally 
    { 
     HibernateUtil.closeCurrentSession(); 
    } 
} 

/** 
* Fecha a Session corrente 
*/ 
public static void closeCurrentSession() 
{ 
    HibernateUtil.sessions.get().close(); 
    HibernateUtil.sessions.set(null); 
} 

我是否在錯誤的時間結束會議?我應該什麼時候關閉它?我是否以錯誤的方式使用ThreadLocal?我目前沒有改變數據,只是檢索,所以我應該可以讓兩個用戶同時進入相同的頁面。

回答

2

我還沒有運行和測試這段代碼。根據我對Hibernate的理解以及Session和Transaction的工作方式,我認爲下面的代碼應該可以幫助你實現目標。 Reference credit

import java.util.List; 
import java.util.Map; 

import org.hibernate.HibernateException; 
import org.hibernate.Query; 
import org.hibernate.Session; 
import org.hibernate.SessionFactory; 
import org.hibernate.Transaction; 
import org.hibernate.cfg.AnnotationConfiguration; 
import org.hibernate.metamodel.domain.Entity; 

public final class HibernateTLDao { 
    private static final ThreadLocal<Session> threadSession = new ThreadLocal<Session>(); 
    private static final ThreadLocal<Transaction> threadTransaction = new ThreadLocal<Transaction>(); 
    private static SessionFactory sessionFactory; 

    static { 
     sessionFactory = new AnnotationConfiguration().configure().buildSessionFactory(); 
    } 

    public List<? extends Entity> executesNamedQuery(final String query, final Map<String, Object> parameters) { 
     beginTransaction(); 
     final Query namedQuery = threadSession.get().getNamedQuery(query); 
     if (parameters != null) { 
      for (final String paramName : parameters.keySet()) { 
       namedQuery.setParameter(paramName, parameters.get(paramName)); 
      } 
     } 
     @SuppressWarnings("unchecked") 
     final List<? extends Entity> result = namedQuery.list(); 
     commitTransaction(); 
     return result; 
    } 

    public static Session getCurrentSession() { 
     Session s = threadSession.get(); 
     try { 
      if (s == null || !s.isOpen()) { 
       s = sessionFactory.openSession(); 
       threadSession.set(s); 
      } 
     } catch (HibernateException ex) { 
      ex.printStackTrace(); 
     } 
     return s; 
    } 

    public static void closeSession() { 
     try { 
      final Session s = threadSession.get(); 
      if (s != null && s.isOpen()) { 
       s.close(); 
      } 
     } catch (HibernateException ex) { 
      ex.printStackTrace(); 
     } finally { 
      threadSession.set(null); 
     } 
    } 

    public static void beginTransaction() { 
     Transaction tx = threadTransaction.get(); 
     try { 
      if (tx != null && !tx.isActive()) { 
       tx = null; 
       threadTransaction.set(null); 
      } 
      if (tx == null) { 
       if (threadSession.get() != null && threadSession.get().isOpen()) { 
        threadSession.get().close(); 
        threadSession.set(null); 
       } 
       tx = getCurrentSession().beginTransaction(); 
       threadTransaction.set(tx); 
      } 
     } catch (HibernateException ex) { 
      ex.printStackTrace(); 
     } finally { 
      if (threadSession.get() == null || !threadSession.get().isOpen()) { 
       getCurrentSession(); 
      } else { 
       threadSession.get().clear(); 
      } 
     } 
    } 

    public static void commitTransaction() { 
     final Transaction tx = threadTransaction.get(); 
     try { 
      if (tx != null && !tx.wasCommitted() && !tx.wasRolledBack()) { 
       Session s = getCurrentSession(); 
       s.flush(); 
       tx.commit(); 
      } 
     } catch (HibernateException ex) { 
      rollbackTransaction(); 
      ex.printStackTrace(); 
     } finally { 
      threadTransaction.set(null); 
      closeSession(); 
     } 
    } 

    public static void rollbackTransaction() { 
     final Transaction tx = threadTransaction.get(); 
     try { 
      if (tx != null && !tx.wasCommitted() && !tx.wasRolledBack()) { 
       tx.rollback(); 
      } 
     } catch (HibernateException ex) { 
      ex.printStackTrace(); 
     } finally { 
      threadTransaction.set(null); 
      closeSession(); 
     } 
    } 
} 
+0

如果這樣做或不能解決您的問題,請隨時發表評論。 – SyntaX

+0

這解決了我的問題,關閉其他會話的線程,是的,非常感謝。但由於某種原因,一個奇怪的空指針異常仍在發生,就像每個線程正在干擾其他變量和流程一樣。我認爲Tomcat本該處理這種行爲?你有什麼想法可能。只有當我在兩個屏幕上同時點擊鏈接時。 – StudioWorks

+0

請提供完整的異常堆棧跟蹤。這將幫助我理解拋出異常的方法。 – SyntaX