StaleObjectstateException行已更新或删除

时间:2010-07-01 13:59:28

标签: java hibernate spring exception staleobjectstate

我在使用hibernate的基于spring框架的Web应用程序的控制器中获得此异常。我已经尝试了很多方法来解决这个问题,但无法解决它。

在控制器的方法handleRequestInternal中,对数据库的调用主要是“读取”,除非是提交操作。 我一直在使用Spring的Session但转移到getHibernateTemplate()并且问题仍然存在。

基本上,这次对数据库的第二次调用会引发此异常。那就是:

1)getEquipmentsByNumber(number) {首先,根据'数字'从数据库中提取设备,该设备具有属性列表,每个属性都有一个值列表。我遍历这些值(原始对象字符串)以读入变量)

2)getMaterialById(id) {提取基于ID的资料}

我确实理解第二次调用很可能是使会话“刷新”,但我只是“读取”对象,那么为什么第二次调用会在Equipment属性上抛出过时的对象状态异常没有改变?

我无法在调用后清除缓存,因为它会导致我传递给视图的对象出现LazyExceptions。

我读过这个: https://forums.hibernate.org/viewtopic.php?f=1&t=996355&start=0 但根据提供的建议无法解决问题。

我该如何解决这个问题?任何想法和想法都表示赞赏。

更新 我刚刚测试的是在函数getEquipmentsByNumber()中从属性列表中读取变量之后,我这样做:getHibernateTemplate().flush();现在异常就在这一行而不是调用fetch材料(即getMaterialById(id))。

更新 在显式调用flush之前,我从会话缓存中删除了对象,以便缓存中没有过时的对象。

getHibernateTemplate().evict(equipment);
getHibernateTemplate().flush();

好的,现在问题已经转移到我执行此操作后从DB中的下一次提取。我想我必须将方法标记为已同步,并在我阅读完内容后立即逐出对象!听起来不太好。

更新 使handleRequestInternal方法“同步”。错误消失了。当然,不是最好的解决方案,而是做什么! 试图在handleRequestInternal关闭当前会话并开启一个新会话。但它会导致应用程序的其他部分无法正常工作。试图使用不起作用的ThreadLocal

4 个答案:

答案 0 :(得分:6)

你错误地使用了Hibernate,导致它认为你正在更新从数据库中删除对象。

这就是为什么调用flush()会抛出异常。

一种可能性:您通过servlet或控制器的成员字段错误地“共享”会话或实体。这是'同步'会改变你的错误症状的主要原因。简短的解决方案:不要这样做。会话和实体不应该&不要这样工作 - 每个请求都应该独立处理。

另一种可能性: unsaved-value默认为“int”PK字段为0。如果你真的想使用0作为有效的PK值,你可以将它们输入为“整数”。

第三个建议:明确使用Hibernate Session,学习编写简单正确的代码,然后加载Hibernate / Spring库的Java源码,这样你就可以阅读&了解这些库实际上为您做了什么。

答案 1 :(得分:3)

我也一直在努力解决这个异常问题,但是当它对对象进行锁定时(即在测试环境中,我知道我是唯一接触对象的过程),它继续复发时,我决定给出堆栈跟踪中的括号内容的适当考虑。

  

org.hibernate.StaleObjectStateException:行已更新或删除   另一个事务(或unsaved-value映射不正确):   [com.rc.model.mexp.MerchantAccount#59132]

在我们的案例中,事实证明映射是错误的;我们在数据库中作为中间文本类型的一个字段的映射中有type="text",并且似乎Hibernate真的很讨厌这种情况,至少在某些情况下。我们从该字段的映射中完全删除了类型规范,问题得到了解决。

现在奇怪的是,在我们的生产环境中,假设有问题的映射,我们不会得到这个例外。有没有人知道为什么会这样?我们使用相同版本的MySQL - “5.0.22-log”(我不知道“-log”的含义) - 在dev和production envs中。

答案 2 :(得分:2)

这里有3种可能性(因为我不确切知道,你正在使用哪种hibernate会话处理)。一个接一个地添加并测试:

在父对象和子对象之间使用inverse=true的双向映射,因此父或子的更改将正确传播到关系的另一端。

使用TimeStampVersion

添加对乐观锁定的支持

使用加入查询一起获取整个对象图[parent + children],以避免第二次调用。

最后,当且仅当无效时 再次通过Id加载父项(您已经拥有)并填充已修改的数据然后更新。

生活会很好! :)

答案 3 :(得分:0)

这个问题是我经历过的并且非常令人沮丧,尽管你的DAO / Hibernate调用中有一些奇怪的事情,因为如果你通过ID进行查找,就没有理由得到陈旧状态,因为这只是对象的简单查找。

首先,确保所有方法都使用@Transaction(required=true) // you'll have to look up the exact syntax

进行注释

但是,当您尝试对从其检索的会话中分离的对象进行更改时,通常会抛出此异常。对此的解决方案通常不简单,需要更多代码发布,以便我们可以准确地看到正在发生的事情;我的一般建议是创建一个@Service,在一次交易中执行这些事情