Hi,
I'm having problems with the Interceptor's afterTransactionCompletion method not being called in a CMT environment.
Hibernate version:
3.0.3/3.0.5
The configuration (extracted from the log):
14:58:22,070 DEBUG Configuration:1117 - hibernate.transaction.factory_class=org.hibernate.transaction.CMTTransactionFactory
14:58:22,070 DEBUG Configuration:1117 - transaction.auto_close_session=true
14:58:22,070 DEBUG Configuration:1117 - transaction.flush_before_completion=true
14:58:22,070 DEBUG Configuration:1117 - connection.release_mode=after_statement
14:58:22,086 DEBUG Configuration:1117 - hibernate.transaction.manager_lookup_class=org.hibernate.transaction.WeblogicTransactionManagerLookup
14:58:22,086 DEBUG Configuration:1117 - jta.UserTransaction=java:comp/UserTransaction
14:58:22,086 DEBUG Configuration:1117 - query.factory_class=org.hibernate.hql.classic.ClassicQueryTranslatorFactory
The code:
MyInterceptor interceptor = new MyInterceptor();
Session session = mySessionFactory.openSession(interceptor);
session.saveOrUpdate(myObj);
Based on the configuration and according to the spec, Hibernate will automatically flush and close the session.
The problem is that MyInterceptor's afterTransactionCompletion method is never called to signal a successful tx commit.
Following is an extract of the Hibernate log:
15:09:43,141 DEBUG SessionImpl:265 - closing session
15:09:43,141 DEBUG CacheSynchronization:40 - transaction before completion callback
15:09:43,141 DEBUG CacheSynchronization:57 - automatically flushing session
15:09:43,141 DEBUG SessionImpl:319 - automatically flushing session
15:09:43,141 DEBUG JDBCContext:238 - before transaction completion
15:09:43,141 DEBUG SessionImpl:368 - before transaction completion
15:09:43,204 DEBUG CacheSynchronization:68 - transaction after completion callback, status: 3
15:09:43,204 DEBUG JDBCContext:243 - after transaction completion
15:09:43,204 DEBUG SessionImpl:399 - after transaction completion
Tracing the Hibernate code led me to the
org.hibernate.jdbc.JDBCContext class, the
registerSynchronizationIfPossible() method; this method creates an instance of
org.hibernate.transaction.CacheSynchronization - basically it registers a
javax.transaction.Synchronization implementation with the container managed TX. The issue is that the CacheSynchronization constructor is called with a NULL value for the
org.hibernate.Transaction parameter.
Code:
javax.transaction.Transaction tx = tm.getTransaction();
if ( isJTATransactionInProgress(tx) ) {
tx.registerSynchronization( new CacheSynchronization(owner, this, tx, null) );
isTransactionCallbackRegistered = true;
log.debug("successfully registered Synchronization");
return true;
}
else {
log.debug("no active transaction, could not register Synchronization");
return false;
}
This means that when the CacheSynchronization's
afterCompletion() callback is invoked by the container, the same NULL value will be passed through all the way to the
org.hibernate.impl.SessionImpl's
afterTransactionCompletion(boolean success, Transaction tx) method, that executes the following:
Code:
if ( isRootSession && tx!=null ) {
try {
interceptor.afterTransactionCompletion(tx);
}
catch (Throwable t) {
log.error("exception in interceptor beforeTransactionCompletion()", t);
}
}
Because
tx is null, the Interceptor's method will not be called.
The JDBCContext method
registerSynchronizationIfPossible() is also be called by some of the
org.hibernate.Transaction implementations (ex. CMTTransaction). Not even in this case is the current Hibernate TX passed to the CacheSynchronization constructor.
Can the Hibernate team please help ? Should this become a JIRA issue ?!
Many thanks !
Regards,
Eugen