]
Steve Ebersole closed HHH-1578.
-------------------------------
Closing stale resolved issues
queries inside events - scenario which fails + fix
---------------------------------------------------
Key: HHH-1578
URL:
http://opensource.atlassian.com/projects/hibernate/browse/HHH-1578
Project: Hibernate Core
Issue Type: Bug
Components: core
Affects Versions: 3.1.2
Reporter: Tomasz Bech
Assignee: Steve Ebersole
It is related to the forum topic:
http://forum.hibernate.org/viewtopic.php?p=2294885#2294885. However I put full and better
description below.
preInsert event is used to make query on DB - to check some integrity.
Following scenario fails:
- insert object A;
- insert object A'; (of type A, but different values than before)
- commit;
it gives stack trace:
This gives exception:
aused by: org.hibernate.exception.GenericJDBCException: could not insert:
at
org.hibernate.exception.SQLStateConverter.handledNonSpecificException(SQLStateConverter.java:91)
at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:79)
at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:43)
at
org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2078)
at
org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2427)
at org.hibernate.action.EntityInsertAction.execute(EntityInsertAction.java:51)
at org.hibernate.engine.ActionQueue.execute(ActionQueue.java:243)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:227)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:140)
at
org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:296)
at
org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:27)
at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1009)
at org.hibernate.impl.SessionImpl.managedFlush(SessionImpl.java:356)
at
org.hibernate.transaction.CacheSynchronization.beforeCompletion(CacheSynchronization.java:59)
at org.jboss.tm.TransactionImpl.doBeforeCompletion(TransactionImpl.java:1473)
at org.jboss.tm.TransactionImpl.beforePrepare(TransactionImpl.java:1092)
at org.jboss.tm.TransactionImpl.commit(TransactionImpl.java:306)
... 63 more
Caused by: java.sql.SQLException: Connection handle has been closed and is unusable
at
org.jboss.resource.adapter.jdbc.WrappedConnection.checkStatus(WrappedConnection.java:526)
at
org.jboss.resource.adapter.jdbc.WrappedConnection.checkTransaction(WrappedConnection.java:513)
at
org.jboss.resource.adapter.jdbc.WrappedStatement.checkTransaction(WrappedStatement.java:537)
at
org.jboss.resource.adapter.jdbc.WrappedPreparedStatement.executeUpdate(WrappedPreparedStatement.java:223)
at org.hibernate.jdbc.NonBatchingBatcher.addToBatch(NonBatchingBatcher.java:23)
at
org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2062)
... 76 more
Following scenario works fine:
- insert object A
- commit;
Following scenario also works fine:
- insert object A
- insert object B
- commit;
I've spend a day to analyze the problem, as the preInsert+queries are crucial for our
project.
The order of operations is as follows:
- prepareBatchStatement is called on AbstractBatcher;
- my suplied query is executed;
- prepareBatchStatement is called on AbstractBatcher;
The problem appears because the 'batchUpdate' statement is reused in second
call:
public PreparedStatement prepareBatchStatement(String sql)
throws SQLException, HibernateException {
sql = getSQL( sql );
if ( !sql.equals(batchUpdateSQL) ) {
batchUpdate=prepareStatement(sql); // calls executeBatch()
batchUpdateSQL=sql;
}
else {
log.debug("reusing prepared statement"); //here - REUSING prepare statement
log(sql);
}
return batchUpdate;
}
and it is why insert A, preinsert-query, insert B scenario works, and insert A,
preinsert-query, query A' doesn't.
The query which was called just before the second insert of A' has closed its
connection, but this connection belongs to batchUpdate too :(.
The function responsible for tracking if the connection cen be closed is:
public boolean hasOpenResources() {
return resultSetsToClose.size() > 0 || statementsToClose.size() > 0 ;
}
It simply doesn't take into consideration that batchUpdate also has open connection -
batchUpdate is not added to the statementsToClose also (as it is in the
prepareQueryStatement).
Golden patch would be to add batchUpdate to the statementsToClose map.
But the same can be reach by (this is a fix):
public boolean hasOpenResources() {
return resultSetsToClose.size() > 0
|| statementsToClose.size() > 0
|| batchUpdate != null;
}
BatchUpdate when executed (in executeBatch) is closed and set to null = its connection
can be released.
I've tested the change, there is no side-effects (no leaked open connections) and the
above scenario works.
(in fact full execution order is: preInsert-query, insert A, preInsert--query, insert
A', but the first preInsert-query works ok.)
--
This message is automatically generated by JIRA.
-
If you think it was sent incorrectly contact one of the administrators: