|
Folks,
We've been experiencing some weird issues on our code when combining JTA container-managed transactions thru Spring Data while using optimistic locking strategy (@Version). When we do calls to any method which executes persistence operations on the database, a StaleObjectStateException is thrown by Hibernate.
We made absolute sure we weren't running two operations inside the same transaction. Using a high-level debug we could see the ORM launches UPDATE queries twice to the DB (code below). After much working on this, we came to a plethora of Google results, much of them pointing to the same StackOverflow solution: [Answer:http://stackoverflow.com/questions/23138497/spring-data-jpa-on-jboss-eap-6-1-org-hibernate-staleobjectstateexception-row]
The code we usually see (on all entities annotated with @Version) is this:
update
"DB_NAME"."TABLE_NAME"
set
[some fields here]
where
[...]
and "UPCNUVER"=? [This is the version field]
2015-03-19 19:47:58,689 TRACE org.hibernate.type.descriptor.sql.BasicBinder - binding parameter [12] as [BIGINT] - [0]
[Second update happens below here]
2015-03-19 19:47:59,433 DEBUG org.hibernate.SQL -
update
"DB_NAME"."TABLE_NAME"
set
[some fields here]
where
[...]
and "UPCNUVER"=? [This is the version field]
Hibernate:
2015-03-19 19:47:59,434 TRACE org.hibernate.type.descriptor.sql.BasicBinder - binding parameter [12] as [BIGINT] - [0]
After this runs, the StaleObjectStateException is thrown. If it helps anything, this is the StackTrace.
weblogic.transaction.RollbackException: setRollbackOnly called on transaction
at weblogic.transaction.internal.TransactionImpl.throwRollbackException(TransactionImpl.java:1878)
at weblogic.transaction.internal.ServerTransactionImpl.internalCommit(ServerTransactionImpl.java:359)
at weblogic.transaction.internal.ServerTransactionImpl.commit(ServerTransactionImpl.java:250)
at weblogic.ejb.container.internal.BaseRemoteObject.postInvoke1(BaseRemoteObject.java:374)
at weblogic.ejb.container.internal.StatelessRemoteObject.postInvoke1(StatelessRemoteObject.java:20)
at weblogic.ejb.container.internal.BaseRemoteObject.__WL_postInvokeTxRetry(BaseRemoteObject.java:226)
at weblogic.ejb.container.internal.SessionRemoteMethodInvoker.invoke(SessionRemoteMethodInvoker.java:47)
at com.vale.mi.gpvm.ete.services.impl.EventoTempoEquipamentoServiceImpl_ndcdgg_EventoTempoEquipamentoServiceImpl.findById(Unknown Source)
at com.vale.mi.gpvm.ete.services.impl.EventoTempoEquipamentoServiceImpl_ndcdgg_EventoTempoEquipamentoServiceImpl_WLSkel.invoke(Unknown Source)
at weblogic.rmi.internal.BasicServerRef.invoke(BasicServerRef.java:693)
at weblogic.rmi.cluster.ClusterableServerRef.invoke(ClusterableServerRef.java:230)
at weblogic.rmi.internal.BasicServerRef$1.run(BasicServerRef.java:519)
at weblogic.security.acl.internal.AuthenticatedSubject.doAs(AuthenticatedSubject.java:363)
at weblogic.security.service.SecurityManager.runAs(SecurityManager.java:146)
at weblogic.rmi.internal.BasicServerRef.handleRequest(BasicServerRef.java:515)
at weblogic.rmi.internal.wls.WLSExecuteRequest.run(WLSExecuteRequest.java:118)
at weblogic.work.ExecuteThread.execute(ExecuteThread.java:295)
at weblogic.work.ExecuteThread.run(ExecuteThread.java:254)
Caused by: weblogic.transaction.internal.AppSetRollbackOnlyException: setRollbackOnly called on transaction
at weblogic.transaction.internal.TransactionImpl.setRollbackOnly(TransactionImpl.java:542)
at org.glassfish.transaction.TransactionManagerImplCommon.setRollbackOnly(TransactionManagerImplCommon.java:568)
at org.glassfish.transaction.TransactionManagerImplCommon.setRollbackOnly(TransactionManagerImplCommon.java:561)
at org.hibernate.engine.transaction.internal.jta.CMTTransaction.markRollbackOnly(CMTTransaction.java:131)
at org.hibernate.engine.transaction.internal.TransactionCoordinatorImpl.setRollbackOnly(TransactionCoordinatorImpl.java:326)
at org.hibernate.engine.transaction.synchronization.internal.SynchronizationCallbackCoordinatorNonTrackingImpl.setRollbackOnly(SynchronizationCallbackCoordinatorNonTrackingImpl.java:124)
at org.hibernate.engine.transaction.synchronization.internal.SynchronizationCallbackCoordinatorNonTrackingImpl.beforeCompletion(SynchronizationCallbackCoordinatorNonTrackingImpl.java:114)
at org.hibernate.engine.transaction.synchronization.internal.RegisteredSynchronization.beforeCompletion(RegisteredSynchronization.java:50)
at weblogic.transaction.internal.ServerSCInfo.doBeforeCompletion(ServerSCInfo.java:1271)
at weblogic.transaction.internal.ServerSCInfo.callBeforeCompletions(ServerSCInfo.java:1244)
at weblogic.transaction.internal.ServerSCInfo.startPrePrepareAndChain(ServerSCInfo.java:126)
at weblogic.transaction.internal.ServerTransactionImpl.localPrePrepareAndChain(ServerTransactionImpl.java:1354)
at weblogic.transaction.internal.ServerTransactionImpl.globalPrePrepare(ServerTransactionImpl.java:2171)
at weblogic.transaction.internal.ServerTransactionImpl.internalCommit(ServerTransactionImpl.java:283)
The StaleObjectStateException is "masked" by this weblogic's RollbackException. If we put a breakpoint inside TransactionImpl we can see it happening.
All this seems to us to be a transaction synchronization issue. But we couldn't go further on this because of the lack of use cases for this.
Is there any way this combination or this specific use case could generate a bug ?
Thanks in advance,
Gustavo
|