我在 Spring 的侦听器中使用 Hibernate DefaultMessageLisenerContainer
。
当我让监听器使用多个线程运行时,我经常会遇到这种StaleStateException
只读操作:
Query q = session.createQuery("SELECT k FROM Keyword k WHERE k.name = :name").setParameter("name", keywordName);
List<Keyword> kws = q.list()
在 q.list() 处抛出异常:
乐观锁定失败;嵌套异常是 org.hibernate.StaleObjectStateException:行已被另一个事务更新或删除(或未保存值映射不正确)
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)
这真的很奇怪,因为读取操作应该从 DB 读取一个新副本,而不是检查版本冲突并抛出StaleObjectStateException
。
该name
属性不是 Keyword 对象的主键。
更新:我的数据访问代码:我正在使用HibernateTransactionManager
支持线程绑定 Hibernate 会话的 Spring。通过 SessionFactory.getCurrentSession() 方法检索 Hibernate 会话。
每个事务通过将 HibernateTransactionManager 分配给 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>
更新: 在建议的答案中,可能有其他操作导致 staleObjectStateException。对于之前的所有其他操作,我已经尝试注销 Session.isDirty()。它们都是读操作。有趣的是,在关键字 select by name 操作之后,会话实际上被标记为脏。实际的代码是这样的:
for (String n : keywordNames) {
Keyword k = keywordDao.getKeywordByName(n);
}
在第一次迭代后会话是脏的。(KeywordDao.getKeywordByName 实现如上)。任何的想法 ?谢谢,库。