【问题标题】:Session is closed Exception会话关闭异常
【发布时间】:2013-04-09 21:07:34
【问题描述】:

我正在使用 Struts 2 hibernate spring 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>  

【问题讨论】:

  • 如果你在出错的地方也贴出代码,可能会得到更好的响应。
  • @JennyD 事实上它并没有发生在一个地方。当我执行一些查询时,我随机发生。每次测试时,我都会在不同的查询中遇到异常。它只发生在我与同时用户打交道时。这一次,当我遇到 20 个并发用户时,我只有一次。
  • 我正在考虑检查连接是否打开并在必要时打开新连接的代码部分。
  • @JennyD 实际上在我执行查询时正在这样做。我仍然得到例外
  • 我知道您每次执行查询时都会这样做。我想说的是,如果你展示如何你这样做,它可能对想要帮助你的人有用。

标签: mysql hibernate struts2 spring-3 c3p0


【解决方案1】:

您可能可以很容易地解决最直接的问题。让您的 closeHibernateSession() 可靠地将 hibernateSession 设置为 null。这将强制您的查询函数创建新的会话,而不是尝试重用旧的、关闭的会话。

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

您需要更清晰地组织休眠会话。从上面的代码中,很明显你有一个名为 hibernateSession 的成员变量,它可以由多个调用者或多个查询共享,有时为空,有时不为空,各种函数延迟初始化,但可能直到一段时间后才会关闭线。这一点都不好。

在最简单的安排中,不要将会话作为成员变量。将其保存为局部变量。让 openHibernateSession() 返回一个会话,该会话将在 finally 块中完全确定地关闭。如果由于某种原因您需要会话比单个函数调用可以封装的内容更长(当然,这可能会调用许多其他函数,每个函数都可能将会话作为参数),您将必须非常非常小心。打开的会话必须可靠地关闭(),并且您必须了解它们的生命周期。您当前的方法,如果一个会话已经打开,则使用一个会话,否则创建一个临时会话,这是不好的。如果你坚持要维护一个 Session 成员变量,你必须非常确定地知道,无论何时初始化成员变量,它究竟是如何以及何时被 close()ed 然后重置为 null 或取消引用以进行垃圾回收。

您还应该了解您的交易,这些都不是“如果我在 close() 之前有未提交的交易,请提交它。”

另外,请考虑迁移到 c3p0-0.9.2.1

【讨论】:

    【解决方案2】:

    当您尝试保存或更新瞬态实例时,请确保与实例关联的实体是持久的。这是用户尝试使用分离的引用持久化实体的新实例的常见错误。在将实体引用设置为要持久化的瞬态或分离实例之前,从持久化上下文中获取实体。

    【讨论】:

    • 目前我不仅在保存或更新时收到此错误。当我尝试获取一些数据时,我也会得到这个。
    • 那你搞乱了连接配置。当您获取一些数据时,连接关闭。发布您的 c3p0 和休眠属性。
    • 我添加了出现异常的代码部分,请检查并提供宝贵的建议
    • 如果您手动管理每个线程的会话,那么您应该在事务后关闭它。你没有在第二次找到。我看不到它是否使用过,你是如何实现会话概念的,看不到。
    • 在第一次查找中,您可以在关闭会话的情况下执行查询。格式化代码,以便我可以看到代码中断的位置。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-01-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多