我正在使用带有扩展会话/自动版本控制的标准乐观并发控制方案。我有一个实体,我在第一个事务中加载,呈现给用户进行修改并保存在第二个事务中,两个事务共享同一个会话。在以某种方式修改实体后,在第二个事务结束时session.flush()
可能会抛出StaleObjectStateException
,以防检测到版本不一致,这意味着并发事务已在其间保存了实体的下一个版本。
我想以最简单的方式处理这样的错误 - 只是为了重新加载失去当前更改的实体并继续编辑并再次保存。首先我尝试了这个:
session.refresh(entity);
但是在我修改并尝试保存这个刷新的实体之后,我仍然得到相同的StaleObjectStateException
,即使它确实被刷新并且版本号看起来是一致的;是的我知道在扩展会话中使用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()
不一样吗?
要恢复,我的问题是:
StaleObjectStateException
仍会在重新加载的实体上抛出,除非session.clear()
已完成?refresh()
错误的正确方法是什么?这种实现对话的方法有问题吗?我正在使用Hibernate 4.1.7.Final,没有二级缓存。
如果我的问题重复,我道歉,但我找不到深刻的解释......
答案 0 :(得分:2)
当您在会话中收到异常时,该会话实例会被破坏。您不能再使用该实例,您必须将其丢弃并创建一个新实例。异常没有重置(因为你可以看到你再次得到相同的异常,从逻辑上认为这不应该发生)。这是使用hibernate会话的一般规则。原因是,hibernate并不总是看到为什么会出现异常并且会话实例的状态可能不一致。
我不知道为什么它在clear()之后有效。这可能是偶然的。使用新实例更为谨慎。
如果您使用StatelessSession,那么您没有此限制,但无状态会话还有其他缺点,例如没有缓存。