问题
I am building an application with Struts 2 hibernate spring 3 with my sql as back end and c3p0 connection pooling(c3p0-0.9.1.1 jar).
Sometimes, when executing a query, I get the below error. When ever I am executing query I check if the connection is closed or not, and if it's closed I will open a new connection before executing the query.
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>
回答1:
you can probably fix your most immediate problem pretty easily. have your closeHibernateSession() reliably set hibernateSession to null. that will force your query functions to create new Sessions rather than try to reuse an old, closed session.
but don't just do this. you have much bigger problems.
you need to be much cleaner in how you organize your hibernate sessions. from the code above, it's clear that you have a member variable called hibernateSession that may be shared by across multiple callers or by multiple queries, that is sometimes null and sometimes not, which various functions lazily initialize but may not close until some time down the line. that's no good at all.
in the simplest arrangement, don't hold the session as a member variable. hold it as a local variable. let openHibernateSession() return a session that will be closed with perfect certainty in a finally block. if for some reason you need sessions to outlive what can be encapsulated by a single function call (which might of course call many other functions, each of which might take the session as a parameter), you will have to be very, very careful. sessions that are open must reliably be close()ed, and you must understand their lifecycles. your current approach, which uses a session if one is already open, but creates a temporary session otherwise, is no good. if you insist on maintaining a Session member variable, you must know with perfect certainty, whenever the member variable will be initialized, exactly how and when it will be close()ed and then reset to null or dereferenced for garbage collection.
you also should understand your transactions, none of this "if i have an uncommitted transaction before close(), commit it."
also, please consider migrating to c3p0-0.9.2.1
回答2:
When you are trying to save or update a transient instance make sure the entities associated with instance are persistent. This is a common error of users trying to persist a new instance of the entity with the detached references. Get the entity from the persistence context before you set its reference to the transient or detached instance that you are going to persist.
来源:https://stackoverflow.com/questions/16054362/session-is-closed-exception