Details
Description
In previous releases, Spring was swallowing Hibernate exceptions within the TransactionSynchronization beforeCompletion method. For more detail see the following link:
http://opensource.atlassian.com/projects/spring/browse/SPR-2270
As the JIRA issue states, the issue was addressed by letting the runtime exception through, but still calling setRollbackOnly.
The issue is that with this fix within Weblogic 8.1, even though Spring lets the exception propogate up, Weblogic will always output a vague AppSetRollbackOnlyException cause whenever setRollbackOnly is invoked. Hence, the underlying exception is still hidden from the developer.
We applied the Spring 2.X fix to our version of Spring 1.2.5.
public void beforeCompletion() {
try
catch (RuntimeException ex)
{ setRollbackOnlyIfPossible(); throw ex; }catch (Error err)
{ setRollbackOnlyIfPossible(); throw err; }finally
{ // Unbind the SessionHolder from the thread early, to avoid issues // with strict JTA implementations that issue warnings when doing JDBC // operations after transaction completion (e.g. Connection.getWarnings). this.beforeCompletionCalled = true; this.springSessionSynchronization.beforeCompletion(); }}
Notice the code above calls setRollbackOnly and rethrows the exception. With this in place, however, we get the following vague exception from Weblogic:
<Feb 8, 2007 11:51:08 AM EST> <Info> <EJB> <BEA-010051> <EJB Exception occurred during invocation from home: [email protected] threw exception: javax.ejb.TransactionRolledbackLocalException: Error
committing transaction:; nested exception is: weblogic.transaction.internal.AppSetRollbackOnlyException
javax.ejb.TransactionRolledbackLocalException: Error committing transaction:; nested exception is: weblogic.transaction.internal.AppSetRollb
ackOnlyException
weblogic.transaction.internal.AppSetRollbackOnlyException
at weblogic.transaction.internal.TransactionImpl.setRollbackOnly()V(TransactionImpl.java:504)
at weblogic.transaction.internal.TransactionManagerImpl.setRollbackOnly()V(TransactionManagerImpl.java:337)
at weblogic.transaction.internal.TransactionManagerImpl.setRollbackOnly()V(TransactionManagerImpl.java:331)
at org.springframework.transaction.jta.UserTransactionAdapter.setRollbackOnly()V(UserTransactionAdapter.java:86)
at org.springframework.orm.hibernate3.SessionFactoryUtils$JtaSessionSynchronization.setRollbackOnlyIfPossible()V(SessionFactoryUtils
.java:1030)
at org.springframework.orm.hibernate3.SessionFactoryUtils$JtaSessionSynchronization.beforeCompletion()V(SessionFactoryUtils.java:100
8)
at weblogic.transaction.internal.ServerSCInfo.callBeforeCompletions(Lweblogic.transaction.internal.TransactionImpl;)V(ServerSCInfo.j
ava:1010)
at weblogic.transaction.internal.ServerSCInfo.startPrePrepareAndChain(Lweblogic.transaction.internal.ServerTransactionImpl;I)V(Serve
rSCInfo.java:115)
at weblogic.transaction.internal.ServerTransactionImpl.localPrePrepareAndChain()V(ServerTransactionImpl.java:1216)
at weblogic.transaction.internal.ServerTransactionImpl.globalPrePrepare()V(ServerTransactionImpl.java:1990)
at weblogic.transaction.internal.ServerTransactionImpl.internalCommit()V(ServerTransactionImpl.java:275)
at weblogic.transaction.internal.ServerTransactionImpl.commit()V(ServerTransactionImpl.java:246)
at weblogic.ejb20.internal.BaseEJBLocalObject.postInvoke(Lweblogic.ejb20.internal.InvocationWrapper;Ljava.lang.Throwable;)V(BaseEJBL
ocalObject.java:363)
at
...
...
We changed the previous patch to not call setRollbackOnly and allow the exception to propogate:
public void beforeCompletion() {
try
finally
{ this.beforeCompletionCalled = true; this.springSessionSynchronization.beforeCompletion(); }}
We now get the underlying exception within our stack trace:
<Feb 8, 2007 12:03:19 PM EST> <Info> <EJB> <BEA-010051> <EJB Exception occurred during invocation from home: [email protected] threw exception: javax.ejb.TransactionRolledbackLocalException: Error
committing transaction:; nested exception is: org.springframework.jdbc.UncategorizedSQLException: Hibernate transaction synchronization; un
categorized SQLException for SQL [insert into MYTABLE (COLUMN1, COLUMN2, COLUMN3, COLUMN4) values (?, ?, ?, ?)]; SQL state [40001]; error code [-911]; DB2 SQL error: SQLCODE: -911, SQLSTATE: 40001, SQLERRMC: 2; nested exce
ption is com.ibm.db2.jcc.a.SqlException: DB2 SQL error: SQLCODE: -911, SQLSTATE: 40001, SQLERRMC: 2
javax.ejb.TransactionRolledbackLocalException: Error committing transaction:; nested exception is: org.springframework.jdbc.UncategorizedSQL
Exception: Hibernate transaction synchronization; uncategorized SQLException for SQL [insert into MYTABLE (COLUMN1, COLUMN2, COLUMN3, COLUMN4) values (?, ?, ?, ?)]; SQL state [40001]; error code [-911]; DB2 SQL error: SQLC
ODE: -911, SQLSTATE: 40001, SQLERRMC: 2; nested exception is com.ibm.db2.jcc.a.SqlException: DB2 SQL error: SQLCODE: -911, SQLSTATE: 40001,
SQLERRMC: 2
org.springframework.jdbc.UncategorizedSQLException: Hibernate transaction synchronization; uncategorized SQLException for SQL [insert into MYTABLE (COLUMN1, COLUMN2, COLUMN3, COLUMN4) values (?, ?, ?, ?)]; SQL state [40001
]; error code [-911]; DB2 SQL error: SQLCODE: -911, SQLSTATE: 40001, SQLERRMC: 2; nested exception is com.ibm.db2.jcc.a.SqlException: DB2 SQ
L error: SQLCODE: -911, SQLSTATE: 40001, SQLERRMC: 2
com.ibm.db2.jcc.a.SqlException: DB2 SQL error: SQLCODE: -911, SQLSTATE: 40001, SQLERRMC: 2
at com.ibm.db2.jcc.a.cq.e(Lcom.ibm.db2.jcc.a.da;)I(cq.java:1482)
at com.ibm.db2.jcc.c.bc.s(Lcom.ibm.db2.jcc.a.ct;)V(bc.java:721)
at com.ibm.db2.jcc.c.bc.k(Lcom.ibm.db2.jcc.a.ct;)V(bc.java:375)
at com.ibm.db2.jcc.c.bc.a(Lcom.ibm.db2.jcc.a.cg;)V(bc.java:63)
at com.ibm.db2.jcc.c.q.a(Lcom.ibm.db2.jcc.a.cg;)V(q.java:64)
at com.ibm.db2.jcc.c.bp.c()V(bp.java:266)
at com.ibm.db2.jcc.a.cr.V()V(cr.java:1412)
at com.ibm.db2.jcc.a.cr.d(IZ)V(cr.java:1939)
at com.ibm.db2.jcc.a.cr.R()I(cr.java:440)
at com.ibm.db2.jcc.a.cr.executeUpdate()I(cr.java:423)
at weblogic.jdbc.wrapper.PreparedStatement.executeUpdate()I(PreparedStatement.java:147)
at org.hibernate.persister.entity.BasicEntityPersister.insert(Ljava.io.Serializable;[Ljava.lang.Object;[ZILjava.lang.String;Ljava.la
ng.Object;Lorg.hibernate.engine.SessionImplementor;)V(BasicEntityPersister.java:1856)
at org.hibernate.persister.entity.BasicEntityPersister.insert(Ljava.io.Serializable;[Ljava.lang.Object;Ljava.lang.Object;Lorg.hibern
ate.engine.SessionImplementor;)V(BasicEntityPersister.java:2200)
at org.hibernate.action.EntityInsertAction.execute()V(EntityInsertAction.java:46)
at org.hibernate.engine.ActionQueue.execute(Lorg.hibernate.action.Executable;)V(ActionQueue.java:239)
at org.hibernate.engine.ActionQueue.executeActions(Ljava.util.List;)V(ActionQueue.java:223)
at org.hibernate.engine.ActionQueue.executeActions()V(ActionQueue.java:136)
at org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(Lorg.hibernate.engine.SessionImplementor;)V(AbstractFlush
ingEventListener.java:274)
at org.hibernate.event.def.DefaultFlushEventListener.onFlush(Lorg.hibernate.event.FlushEvent;)V(DefaultFlushEventListener.java:27)
at org.hibernate.impl.SessionImpl.flush()V(SessionImpl.java:730)
at org.springframework.orm.hibernate3.SessionFactoryUtils$SpringSessionSynchronization.beforeCommit(Z)V(SessionFactoryUtils.java:881
)
at org.springframework.orm.hibernate3.SessionFactoryUtils$JtaSessionSynchronization.beforeCompletion()V(SessionFactoryUtils.java:100
5)
at weblogic.transaction.internal.ServerSCInfo.callBeforeCompletions(Lweblogic.transaction.internal.TransactionImpl;)V(ServerSCInfo.j
ava:1010)
at weblogic.transaction.internal.ServerSCInfo.startPrePrepareAndChain(Lweblogic.transaction.internal.ServerTransactionImpl;I)V(Serve
rSCInfo.java:115)
at weblogic.transaction.internal.ServerTransactionImpl.localPrePrepareAndChain()V(ServerTransactionImpl.java:1216)
at weblogic.transaction.internal.ServerTransactionImpl.globalPrePrepare()V(ServerTransactionImpl.java:1990)
at weblogic.transaction.internal.ServerTransactionImpl.internalCommit()V(ServerTransactionImpl.java:275)
at weblogic.transaction.internal.ServerTransactionImpl.commit()V(ServerTransactionImpl.java:246)
at weblogic.ejb20.internal.BaseEJBLocalObject.postInvoke(Lweblogic.ejb20.internal.InvocationWrapper;Ljava.lang.Throwable;)V(BaseEJBL
ocalObject.java:363)
...
...
I know the JTA 1.0.1 specification does not define the behaviour for exceptions thrown from before completion and this is why spring included the call to setRollbackOnly in addition to rethrowing the exception. The issue is that calling setRollbackOnly yields undesirable exception masking within Weblogic 8.1 even if the exception is rethrown. Since we cannot predict the behaviour of every JTA 1.0.1 container, I think this functionality should be configurable. The problem is that SessionFactoryUtils instanciates the SpringJtaSynchronizationAdapter within a static method making the transaction synchronization behaviour not very customizable.
Thx.
-karl