I am using Hibernate in a listener of Spring DefaultMessageLisenerContainer
.
When I let the listener run with multiple threads, I often encounter this StaleStateException
for a read only operation:
Query q = session.createQuery("SELECT k FROM Keyword k WHERE k.name = :name").setParameter("name", keywordName);
List<Keyword> kws = q.list()
The exception is thrown at q.list():
optimistic locking failed; nested exception is org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect)
Caused by: org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect): [com.aurora.common.model.Keyword#7550]
at org.hibernate.persister.entity.AbstractEntityPersister.check(AbstractEntityPersister.java:1934)
at org.hibernate.persister.entity.AbstractEntityPersister.update(AbstractEntityPersister.java:2578)
at org.hibernate.persister.entity.AbstractEntityPersister.updateOrInsert(AbstractEntityPersister.java:2478)
at org.hibernate.persister.entity.AbstractEntityPersister.update(AbstractEntityPersister.java:2805)
at org.hibernate.action.EntityUpdateAction.execute(EntityUpdateAction.java:114)
at org.hibernate.engine.ActionQueue.execute(ActionQueue.java:267)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:259)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:179)
at org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:321)
at org.hibernate.event.def.DefaultAutoFlushEventListener.onAutoFlush(DefaultAutoFlushEventListener.java:64)
at org.hibernate.impl.SessionImpl.autoFlushIfRequired(SessionImpl.java:1175)
at org.hibernate.impl.SessionImpl.list(SessionImpl.java:1251)
at org.hibernate.impl.QueryImpl.list(QueryImpl.java:102)
It is really strange as read operation should read a fresh copy from DB rather than check for a version conflict and throw StaleObjectStateException
.
The name
attribute is not the primary key of Keyword object.
UPDATE:
My data access code: I am using Spring's HibernateTransactionManager
which support thread-bound Hibernate session. The Hibernate session is retrieved through SessionFactory.getCurrentSession() method.
Each transaction wrap around a invoke of listener by assigning the HibernateTransactionManager to MessageListenerContainer:
<jms:listener-container connection-factory="connectionFactory" concurrency="3-3" prefetch="6" transaction-manager="transactionManager">
<jms:listener destination="${requests}" response-destination="${replies}" ref="chunkHandler" method="handleChunk" />
</jms:listener-container>
UPDATE : As in the suggested answer, there might be other operations causing staleObjectStateException. I have tried logging out the Session.isDirty(), for all other operations prior to that. They are all read operation. Interestingly, the session is actually marked as dirty after the keyword select by name operation. The actual code is something like this:
for (String n : keywordNames) {
Keyword k = keywordDao.getKeywordByName(n);
}
The session is dirty after the first iteration. (KeywordDao.getKeywordByName implmentation is as above). Any idea ? Thanks, Khue.