2015-11-06 55 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