java - 实体重新加载后仍然抛出 Hibernate 的 StaleObjectStateException

标签 java hibernate session optimistic-locking

我正在使用具有扩展 session /自动版本控制的标准乐观并发控制场景。我有一个在第一个事务中加载的实体,呈现给用户进行修改并保存在第二个事务中,两个事务共享同一 session 。以某种方式修改实体后,在第二个事务结束时,session.flush() 可能会抛出 StaleObjectStateException,以防检测到版本不一致,这意味着并发事务已保存介于两者之间的实体的下一个版本。

我想以最简单的方式处理此类错误 - 只需重新加载丢失当前更改的实体并继续再次编辑和保存。首先我尝试了这个:

session.refresh(entity);

但是在我修改并尝试保存这个刷新的实体后,我仍然得到相同的 StaleObjectStateException,即使它确实被刷新并且版本号看起来一致;是的,我知道在扩展 session 中使用 refresh()discouraged ,但不明白为什么。这种行为与不鼓励的原因有关吗?

接下来我尝试了以下方法来避免使用session.refresh():

session.evict(entity);
entity = session.load(MyEntity.class, id);

但它仍然会导致在保存确实不陈旧的实体时引发StaleObjectStateException

我设法应对异常的唯一方法是:

session.clear();
entity = session.load(MyEntity.class, id);

但是 session.clear() 与属于我的具体实体的 session.evict() 不一样吗?

继续,我的问题是:

  • 除非完成 session.clear() 操作,为什么重新加载的实体上仍会引发 StaleObjectStateException
  • 重新加载已在同一 session 中加载的实体的正确方法是什么?为什么 refresh() 不好?这种实现对话的方式有什么问题吗?

我使用的是 Hibernate 4.1.7.Final,没有二级缓存。

如果我的问题重复,我很抱歉,但我找不到深刻的解释......

最佳答案

当您在 session 中遇到异常时,该 session 实例就会被破坏。您不能再使用该实例,必须丢弃它并创建一个新实例。异常不会重置(正如您所看到的,您再次遇到相同的异常,从逻辑上讲,这不应该发生)。这是使用 hibernate session 的一般规则。这样做的原因是,hibernate并不总能看出为什么会出现异常,并且 session 实例的状态可能不一致。

我不知道为什么它在clear()之后起作用。这可能是偶然的。使用新实例更为谨慎。

如果您使用 StatelessSession,则没有此限制,但无状态 session 还有其他缺点,例如没有缓存。

关于java - 实体重新加载后仍然抛出 Hibernate 的 StaleObjectStateException,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13574814/

相关文章:

java - 将对象保存到实体中而不将其保存在 JPA 中

javascript - 为什么类型为 ObjectID (MongoDB) 的 session 参数会转换为字符串?

java - 有没有办法让Javascript在点击刷新后重定向页面( session 已经过期)

java - 如何将监听 hibernate 事件的模块与实体本身分离?

java - 无法评估 Jackson 反序列化的类型

java - 以编程方式使 Java Web 应用程序重新启动时的所有 session 过期

java - 不同时区的两个 java 日期之间经过的天数

java - 如何使用工作队列行为发布到多个队列?

java - 对于始终为 null 的方法参数,NullType 与 Void

java - 在 SmartGWT 5.0 中格式化 TextItem 以显示其数值(以千为单位)