java - 在读取操作中使用 Hibernate 的 StaleObjectStateException?

标签 java spring hibernate spring-integration

我在 Spring DefaultMessageLisenerContainer 的监听器中使用 Hibernate。

当我让监听器以多线程运行时,我经常遇到这种只读操作的StaleStateException:

Query q = session.createQuery("SELECT k FROM Keyword k WHERE k.name = :name").setParameter("name", keywordName);
List<Keyword> kws = q.list()

在 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)

这真的很奇怪,因为读取操作应该从数据库中读取一个新副本,而不是检查版本冲突并抛出 StaleObjectStateException

name 属性不是关键字对象的主键。

更新: 我的数据访问代码:我正在使用支持线程绑定(bind) Hibernate session 的 Spring 的 HibernateTransactionManager。通过 SessionFactory.getCurrentSession() 方法检索 Hibernate session 。

每个事务通过将 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()。它们都是读操作。有趣的是,session 实际上在关键字 select by name 操作后被标记为脏。实际代码是这样的:

for (String n : keywordNames) {
    Keyword k = keywordDao.getKeywordByName(n);
}

session 在第一次迭代后变脏。 (KeywordDao.getKeywordByName 实现如上)。 任何的想法 ?谢谢, 呼。

最佳答案

我认为给出的其他答案不正确。访问不存在的行不会产生 StaleObjectStateException,并且简单地查询实体也不会触发该实体的乐观锁。

进一步检查堆栈跟踪会给出一些原因提示:

在 org.hibernate.impl.QueryImpl.list(QueryImpl.java:102) 当你调用 query.list() 时

at org.hibernate.impl.SessionImpl.autoFlushIfRequired(SessionImpl.java:1175) Hibernate 将确定是否需要自动刷新 session 。由于某种原因,Hibernate 认为需要自动刷新。 (可能是因为您之前已经在同一 session 中对某些关键字实体或其他实体进行了更新……老实说,这是我不能说的)

at org.hibernate.persister.entity.AbstractEntityPersister.update(AbstractEntityPersister.java:2805) 然后 Hibernate 会将 session 中的所有更改刷新到 DB。而且,这里出现了StaleObjectStateException的问题,也就是Optimistic Concurrency check failure。乐观并发检查失败可能与关键字实体相关,也可能不相关(因为它只是将 session 中的所有更新实体刷新到数据库)。但是,在您的情况下,它实际上与 Keyword 实体有关( Caused by: org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect) : [com.ncs.singtel.aurora.common.model.Keyword#7550])

请验证乐观并发失败的原因是什么。通常我们只是将乐观并发异常重新抛给调用者,让调用者决定是否要再次调用该函数。然而,这完全取决于您的设计。

关于java - 在读取操作中使用 Hibernate 的 StaleObjectStateException?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14432813/

相关文章:

java - 我可以创建 spring mvc 自定义验证注释而不链接到 validator 实现吗

java - Hibernate EntityManager 未被注入(inject) - NullPointer

java - 如何在hibernate中使用CreateSqlQuery查询不同的数据库?

java - 从 JList 中删除多个选择

java - 当我更新 JTable 中的数据库时,我得到多个项目

java - 哪个应用层负责提供对外服务集成能力?

java - 如何在没有属性文件的情况下使用 Spring 的 @Value?

java - REST API,何时使用 @PathParam、@QueryParam、@RequestBody 和/或 @RequestHeader

java - Spring Security Java Config 自定义注销处理程序不工作

java - 如何在 Spring Boot 中选择理想的分页方式?