我在使用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
。
答案 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
的双向映射,因此父或子的更改将正确传播到关系的另一端。
使用TimeStamp
或Version
列
使用加入查询一起获取整个对象图[parent + children],以避免第二次调用。
最后,当且仅当无效时
再次通过Id
加载父项(您已经拥有)并填充已修改的数据然后更新。
生活会很好! :)
答案 3 :(得分:0)
这个问题是我经历过的并且非常令人沮丧,尽管你的DAO / Hibernate调用中有一些奇怪的事情,因为如果你通过ID进行查找,就没有理由得到陈旧状态,因为这只是对象的简单查找。
首先,确保所有方法都使用@Transaction(required=true) // you'll have to look up the exact syntax
但是,当您尝试对从其检索的会话中分离的对象进行更改时,通常会抛出此异常。对此的解决方案通常不简单,需要更多代码发布,以便我们可以准确地看到正在发生的事情;我的一般建议是创建一个@Service
,在一次交易中执行这些事情