Details
-
Feature Request
-
Resolution: Done
-
Major
-
jBPM 5.4
-
None
Description
Currently JPAProcessInstanceManager.getProcessInstance() calls ProcessInstanceInfo.updateLastReadDate() so it may result in StaleObjectStateExcpetion even with ksession.getProcessInstance() when there are concurrent accesses to the same process instance.
37762 04/01 12:15:40,813[pool-3-thread-9] ERROR event.def.AbstractFlushingEventListener.performExecutions - Could not synchronize database state with session org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect): [org.jbpm.persistence.processinstance.ProcessInstanceInfo#16] at org.hibernate.persister.entity.AbstractEntityPersister.check(AbstractEntityPersister.java:1782) at org.hibernate.persister.entity.AbstractEntityPersister.update(AbstractEntityPersister.java:2425) at org.hibernate.persister.entity.AbstractEntityPersister.updateOrInsert(AbstractEntityPersister.java:2325) at org.hibernate.persister.entity.AbstractEntityPersister.update(AbstractEntityPersister.java:2625) at org.hibernate.action.EntityUpdateAction.execute(EntityUpdateAction.java:115) 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:168) 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.impl.SessionImpl.managedFlush(SessionImpl.java:366) at org.hibernate.ejb.AbstractEntityManagerImpl$1.beforeCompletion(AbstractEntityManagerImpl.java:504) at bitronix.tm.BitronixTransaction.fireBeforeCompletionEvent(BitronixTransaction.java:478) at bitronix.tm.BitronixTransaction.commit(BitronixTransaction.java:193) at bitronix.tm.BitronixTransactionManager.commit(BitronixTransactionManager.java:120) at org.drools.persistence.jta.JtaTransactionManager.commit(JtaTransactionManager.java:179) at org.drools.persistence.SingleSessionCommandService.execute(SingleSessionCommandService.java:363) at org.drools.command.impl.CommandBasedStatefulKnowledgeSession.getProcessInstance(CommandBasedStatefulKnowledgeSession.java:125) at com.sample.ProcessMainJPA$1.run(ProcessMainJPA.java:61)
Kris wrote:
==========
Whenever a process instance is retrieved when using persistence, the
process instance info is indeed updated with a new last read date. The
most important reason for doing this is for marking the process instance
info object as "dirty" so that when the transaction commits, the process
instance info object (more specifically the processInstanceByteArray)
will be updated with the latest version of the process instance (using
the @PreUpdate update() method).
Note that, if a process instance is only retrieved and not changed, this
is technically not necessary, but if the process instance is updated by
the engine after it is retrieved, this update will obviously be necessary.
I do agree that it involves a small overhead if you're only reading
state (assuming you don't want to use lastReadDate as that will
obviously only work if you update every time you read) but since most
invocations do involve changes to the process instance as well
afterwards, and it's technically not that easy to use another way to
determine when a process instance should be marked dirty (as persistence
is done as a wrapper around the core engine), we decided to just keep
track of the process instances loaded.
One way I can see to optimize this would be to remove the last read date
and, when the transaction commits, verify whether any changes were
actually made, and if not reset the change, so no changes need to be
committed.
==========