我正在使用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>
你可以很容易地解决你最直接的问题。让closeHibernateSession()可靠地将hibernateSession设置为null。这将强制您的查询函数创建新的会话,而不是尝试重用旧的,已关闭的会话。
但不要只是这样做。你有更大的问题。
你需要更清楚地组织你的hibernate会话。从上面的代码中可以清楚地看到,你有一个名为hibernateSession的成员变量,可以由多个调用者或多个查询共享,有时是null,有时不是,各种函数懒惰地初始化但是可能直到某个时间才关闭线。这根本不好。
在最简单的安排中,不要将会话保持为成员变量。把它当作局部变量。让openHibernateSession()返回一个会在finally块中完全确定地关闭的会话。如果由于某种原因,您需要的会话比单个函数调用可以封装的内容更长(当然可以调用许多其他函数,每个函数都可以将会话作为参数),您必须非常非常小心。开放的会话必须可靠地关闭(),你必须了解他们的生命周期。您当前的方法,如果一个会话已经打开,则使用会话,但是否则会创建一个临时会话,这是不好的。如果你坚持维护一个Session成员变量,那么每当成员变量初始化时,你必须完全确定,确切地知道如何以及何时将它关闭(),然后重置为null或取消引用以进行垃圾收集。
你也应该了解你的交易,没有这个“如果我在close()之前有一个未提交的交易,那就提交它。”
另外,请考虑迁移到c3p0-0.9.2.1
当您尝试保存或更新瞬态实例时,请确保与实例关联的实体是持久的。这是用户尝试使用分离引用持久保存实体的新实例时的常见错误。在设置对将要保留的瞬态或分离实例的引用之前,从持久性上下文中获取实体。