I am using Wicket, DataBinder and Hibernate in my application. As part of its operation, Wicket wants to serialize the Hibernate Session. I was getting an error stating that
Code:
<snip>
Caused by: java.lang.IllegalStateException: Cannot serialize a session while connected
at org.hibernate.impl.SessionImpl.writeObject(SessionImpl.java:1928)
<snip>
So, while debugging to find the problem I got to line 1927 in SessionImpl
Code:
if ( !jdbcContext.getConnectionManager().isReadyForSerialization() ) {
When digging into that method, I get to NonBatchingBatcher(AbstractBatcher).hasOpenResources() line: 599
Code:
return resultSetsToClose.size() > 0 || statementsToClose.size() > 0;
What is odd here is that when I inspected the two objects (resultSetsToClose, statementsToClose) their sizes were 4 and 0, repsectively!
So armed with this knowledge and a few more breakpoints, I found that the ResultsSets weren't getting closed when the statements were. It looks like the fact that I had wrap_result_set = true was the problem. When I removed the property from my configuration, I was successful in serializing the Hibernate Session!
So, based upon what I can see, the AbstractBatcher (line 168) gets the resultSet, sticks a ref in a HashSet, and returns the ResultSet.
Code:
public ResultSet getResultSet(PreparedStatement ps) throws SQLException {
ResultSet rs = ps.executeQuery();
resultSetsToClose.add(rs);
logOpenResults();
return rs;
}
It doesn't actually get wrapped in this method, it doesn't happen until line 1780 in Loader
Code:
rs = wrapResultSetIfEnabled( rs , session );
So, when AbstractBatcher.closeQueryStatement() is called (elsewhere) the Statement and ResultSetWrapper are sent (not the original ResultSet), therefore line 201 in AbstractBatcher won't remove the ResultSet from the HashSet
Code:
if (rs!=null) resultSetsToClose.remove(rs);
I'm not real sure what the solution is, possibly:
1. Make ResultSetWrapper's equals/hashCode be based upon the underlying ResultSet object
2. Make closeQueryStatement() check if rs is a Wrapper or not, in order to take the proper action.
3. Anywhere where closeQueryStatement is called, be sure to unwrap the ResultSet first.
You will find my hiberante.cfg.xml below. I hope I was thorough enough to understand my problem. Thanks for any help you can offer.
Chuck
==============================
Hibernate version: Core 3.2.1.ga
Annotations 3.2.0.ga
Mapping documents:Code:
<session-factory>
<property name="hibernate.dialect">org.hibernate.dialect.SQLServerDialect</property>
<property name="hibernate.default_catalog">@aims.db.name@</property>
<property name="hibernate.default_schema">dbo</property>
<property name="hibernate.connection.url">jdbc:@jdbc.vendor@://@aims.db.server@/@aims.db.name@:@aims.db.port@</property>
<property name="hibernate.connection.username">@aims.db.user@</property>
<property name="hibernate.connection.password">@aims.db.password@</property>
<property name="hibernate.connection.driver_class">@jdbc.class@</property>
<property name="hibernate.connection.autocommit">false</property>
<property name="hibernate.connection.release_mode">after_transaction</property>
<property name="hibernate.jdbc.wrap_result_sets">true</property>
<property name="hibernate.cache.use_second_level_cache">true</property>
<property name="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</property>
<property name="hibernate.transaction.factory_class">org.hibernate.transaction.JDBCTransactionFactory</property>
<property name="hibernate.generate_statistics">true</property>
<property name="hibernate.max_fetch_depth">1</property>
<property name="hibernate.query.substitutions">true 1, false 0</property>
</session-factory>
Code between sessionFactory.openSession() and session.close():
session.setFlushMode(FlushMode.MANUAL);
Name and version of the database you are using:
MS SQL Server Standard Edition 2000 SP4