Exceptions being hidden in JDBCTransation
-----------------------------------------
Key: HHH-6607
URL:
http://opensource.atlassian.com/projects/hibernate/browse/HHH-6607
Project: Hibernate Core
Issue Type: Bug
Components: envers
Affects Versions: 3.6.7
Environment: The issue happens when the audit schema is different from the
primary schema say because of a column change. The database session is rolled back but
the exception isn't thrown up to any levels past the
notifyLocalSynchsBeforeTransactionCompletion() so any applications needing to recover from
database failures cannot - say rolling back application caches.
The way to reproduce this is to drop a column in the aud table for any domain object and
try to insert the data
Reporter: Rich Christy
2011-08-24 16:00:15,886 ERROR [AbstractFlushingEventListener] Could not synchronize
database state with session
org.hibernate.exception.SQLGrammarException: Could not execute JDBC batch update
at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:90)
at
org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:66)
at org.hibernate.jdbc.AbstractBatcher.executeBatch(AbstractBatcher.java:275)
at org.hibernate.jdbc.AbstractBatcher.prepareStatement(AbstractBatcher.java:114)
at org.hibernate.jdbc.AbstractBatcher.prepareStatement(AbstractBatcher.java:109)
at
org.hibernate.jdbc.AbstractBatcher.prepareBatchStatement(AbstractBatcher.java:244)
at
org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2242)
at
org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2678)
at org.hibernate.action.EntityInsertAction.execute(EntityInsertAction.java:79)
at org.hibernate.engine.ActionQueue.execute(ActionQueue.java:279)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:263)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:167)
at
org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:321)
at
org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:50)
at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1028)
at
org.hibernate.envers.synchronization.AuditSync.beforeCompletion(AuditSync.java:161)
at
org.hibernate.transaction.JDBCTransaction.notifyLocalSynchsBeforeTransactionCompletion(JDBCTransaction.java:274)
at org.hibernate.transaction.JDBCTransaction.commit(JDBCTransaction.java:140)
at
org.openspaces.persistency.hibernate.DefaultHibernateExternalDataSource.executeBulk(DefaultHibernateExternalDataSource.java:107)
at
com.skyroad.motion.transactionmanager.util.TransactionMirrorExternalDataSource.executeBulk(TransactionMirrorExternalDataSource.java:32)
What the code is doing in the exception handling of AuditSync.java (5th line from the
bottom in the stack track) is rolling back the transaction as far as the hibernate session
is concerned and then unconditionally throwing the exception to the next level. However,
the code in notifyLocalSynchsBeforeTransactionCompletion() eating the exception so
Gigaspaces isn't aware that it happened. This would explain why the database writes
are rolled back but the space isn't.
public void beforeCompletion() {
if (workUnits.size() == 0 && undoQueue.size() == 0) {
return;
}
try {
// see:
http://www.jboss.com/index.html?module=bb&op=viewtopic&p=4178431
if (FlushMode.isManualFlushMode(session.getFlushMode()) ||
session.isClosed()) {
Session temporarySession = null;
try {
temporarySession =
session.getFactory().openTemporarySession();
executeInSession(temporarySession);
temporarySession.flush();
} finally {
if (temporarySession != null) {
temporarySession.close();
}
}
} else {
executeInSession(session);
// Explicity flushing the session, as the auto-flush may
have already happened.
session.flush();
}
} catch (RuntimeException e) {
// Rolling back the transaction in case of any exceptions
//noinspection finally
try {
if (session.getTransaction().isActive()) {
session.getTransaction().rollback();
}
} finally {
//noinspection ThrowFromFinallyBlock
throw e;
}
}
}
private void notifyLocalSynchsBeforeTransactionCompletion() {
if (synchronizations!=null) {
for ( int i=0; i<synchronizations.size(); i++ ) {
Synchronization sync = (Synchronization)
synchronizations.get(i);
try {
sync.beforeCompletion();
}
catch (Throwable t) {
log.error("exception calling user
Synchronization", t);
}
}
}
}
--
This message is automatically generated by JIRA.
For more information on JIRA, see:
http://www.atlassian.com/software/jira