会话关闭异常(Session is closed Exception)

2019-11-02 01:33发布

我建立使用Struts 2 Hibernate的弹簧3应用程序中使用我的SQL作为后端和C3P0连接池(c3p0-0.9.1.1 JAR)。

有时,在执行查询时,我得到下面的错误。 当过我执行查询我检查,如果连接被关闭或没有,如果它关闭,我会打开执行查询之前,一个新的连接。


public List<T> find(final Query query, final Object[] values) throws HibernateException, NullPointerException {  
        if (values != null) {  
            for (int i = 0; i < values.length; i++) {  
                query.setParameter(i, values[i]);  
            }  
        }  
        List<T> resultList = null;  
        if (hibernateSession == null || !hibernateSession.isOpen()) {  
            try {  
                openHibernateSession();  
                resultList = query.list();  
            } catch (Exception e) {  
                e.printStackTrace();  
            } finally {  
                closeHibernateSession();  
            }  
        } else {  
            resultList = query.list();  
        }  
        return resultList;  
    }  

public List<T> find(final String queryString, final Object[] values) throws HibernateException {  
        if (hibernateSession == null || !hibernateSession.isOpen()) {  
            openHibernateSession();  
        }  
        Query queryObject = hibernateSession.createQuery(queryString);  
        return find(queryObject, values);  
    }  

private void openHibernateSession() throws HibernateException {  
    try {  
        hibernateSession = HibernateUtil.getSessionFactory().openSession();  
        hibernateSession.setFlushMode(FlushMode.MANUAL);  
        hibernateTransaction = hibernateSession.getTransaction();  
        hibernateTransaction.begin();  
    } catch (Exception e) {    
        e.printStackTrace();  
    }  

}  

private void closeHibernateSession() {  
    try {  

        if (hibernateTransaction != null) {  
            hibernateSession.flush();  
            if (!hibernateTransaction.wasCommitted()) {  
                hibernateTransaction.commit();  
            }  

        }  
        if (hibernateSession != null) {  
            if (hibernateSession.isOpen()) {  
                hibernateSession.close();  
            }  
        }  
    } catch (Exception e) {  
        e.printStackTrace();  
    }  
}  


    <property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>  
    <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>  
    <property name="hibernate.connection.url">jdbc:mysql://localhost:3306/projectdb</property>  
    <property name="hibernate.connection.username">root</property>  
    <property name="hibernate.connection.password">root</property>  

    <property name="show_sql">true</property>  
    <property name="format_sql">true</property>   

    <property name="hbm2ddl.auto">update</property>  
    <property name="hibernate.c3p0.min_size">5</property>  
    <property name="hibernate.c3p0.max_size">20</property>  
    <property name="hibernate.c3p0.timeout">1800</property>  
    <property name="hibernate.c3p0.max_statements">50</property>  
    <property name="hibernate.c3p0.idle_test_period">50</property>  
    <property name="hibernate.connection.provider_class">org.hibernate.connection.C3P0ConnectionProvider</property>  
    <property name="hibernate.c3p0.acquire_increment">2</property>  

    <property name="hibernate.c3p0.usesTraditionalReflectiveProxies">true</property>  
    <property name="connection.pool_size">20</property>  
    <property name="current_session_context_class">thread</property>  
    <property name="cache.provider_class">org.hibernate.cache.NoCacheProvider</property>  

    <property name="hibernate.connection.isolation">4</property>  

Answer 1:

你也许可以很容易地解决您的最直接的问题。 有你的closeHibernateSession()可靠地设置hibernateSession为null。 这将迫使你的查询功能来创建新的会话,而不是试图重新使用旧的,封闭的会议。

但不只是这样做。 你有更大的问题。

您需要在您组织的Hibernate Session干净多了。 从上面的代码中,很明显,有一个名为hibernateSession一个成员变量,其可以通过在多个呼叫者或多个查询被共享,即有时空有时不是,其各种功能的懒惰地初始化而可能不关闭,直到一段时间然后将线。 这是一点好处都没有。

在最简单的方案,不举行会议的成员变量。 拿着它作为一个局部变量。 让openHibernateSession()返回将与完美的确定性,finally块来关闭会话。 如果由于某种原因,你需要会话活得比有什么可以通过一个函数调用(这可能当然调用许多其它功能,其中的每一个可能采取的会话作为参数)进行封装,你必须是非常,非常小心。 打开的会话必须可靠地接近()的,你必须了解它们的生命周期。 您目前的做法,它使用一个会话,如果一个已经打开,否则会创建一个临时会议,也是白搭。 如果你坚持保持会话的成员变量,你必须知道完美的肯定,每当成员变量将被初始化,究竟怎样及何时会接近()的,然后重新设置为空或解除引用进行垃圾回收。

你也应该了解你的交易,没有这个“如果我有未提交的事务之前关闭(),提交它。”

同时,请考虑迁移到c3p0-0.9.2.1



Answer 2:

当您试图保存或更新一个瞬态的实例确保与实例相关联的实体是持久的。 这是用户试图坚持实体的新实例分离引用的一个常见的错误。 从获取持久化上下文的实体设置的参考,你会坚持瞬态或脱管的实例之前。



文章来源: Session is closed Exception