过时对象状态异常行已由 更新或删除

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

在控制器的方法中,对数据库的调用主要是为了“读取”,除非它是提交操作。我一直在使用,春季会议,但移动到,问题仍然存在。handleRequestInternalgetHibernateTemplate()

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

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

2) {根据 id 获取材料}getMaterialById(id)

我确实知道第二次调用,最有可能的是,使会话“刷新”,但我只是“读取”对象,那么为什么第二次调用会在设备属性上引发过时的对象状态异常,如果没有任何更改?

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

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

我该如何解决这个问题?任何想法和想法都是值得赞赏的。

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

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

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

好了,现在在我完成此操作后,问题已转移到DB的下一次提取。我想我必须将方法标记为同步,并在完成阅读完它们的内容后立即逐出对象!这听起来不是很好。

更新:使方法“同步”。错误消失。当然,这不是最好的解决方案,但该怎么办!已尝试关闭当前会话并打开新会话。但这会导致应用程序的其他部分无法正常工作。尝试使用也不起作用。handleRequestInternalhandleRequestInternalThreadLocal


答案 1

您以某种方式滥用了Hibernate,导致它认为您正在更新从数据库中删除对象。

这就是调用引发异常的原因。flush()

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

另一种可能性:对于“int”PK 字段,未保存值默认为 0。如果您确实希望使用 0 作为有效的 PK 值,则可以将这些值键入为“整数”。

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


答案 2

我也一直在努力解决这个异常,但是当它仍然继续重复出现时,即使我对对象进行了锁定(并且在测试环境中,我知道我是唯一接触该对象的进程),我决定对堆栈跟踪中的括号进行适当的考虑。

org.hibernate.StaleObjectStateException:行被另一个事务更新或删除(或者未保存的值映射不正确):[com.rc.model.mexp.MerchantAccount#59132]

在我们的例子中,事实证明映射是错误的;我们在数据库中的一个字段的映射中是一种媒介文本类型,似乎Hibernate非常讨厌它,至少在某些情况下是这样。我们从此字段的映射中完全删除了类型规范,问题已得到解决。type="text"

现在奇怪的是,在我们的生产环境中,由于存在所谓的问题映射,我们没有得到这个例外。有没有人知道为什么会这样?我们在开发和生产环境中使用相同版本的MySQL - “5.0.22-log”(我不知道“-log”是什么意思)。