Java StaleObjectstateException 行被更新或删除
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/3158491/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
StaleObjectstateException row was updated or deleted by
提问by Saky
I am getting this exception in a controller of a web application based on spring framework using hibernate. I have tried many ways to counter this but could not resolve it.
我在使用休眠的基于 spring 框架的 Web 应用程序的控制器中收到此异常。我尝试了很多方法来解决这个问题,但无法解决。
In the controller's method, handleRequestInternal
, there are calls made to the database mainly for 'read', unless its a submit action.
I have been using, Spring's Session but moved to getHibernateTemplate()
and the problem still remains.
在控制器的方法中,handleRequestInternal
调用数据库主要是为了“读取”,除非它是提交操作。我一直在使用 Spring 的 Session 但转移到getHibernateTemplate()
了,问题仍然存在。
basically, this the second call to the database throws this exception. That is:
基本上,这是对数据库的第二次调用会引发此异常。那是:
1) getEquipmentsByNumber(number)
{ firstly an equipment is fetched from the DB based on the 'number', which has a list of properties and each property has a list of values. I loop through those values (primitive objects Strings) to read in to variables)
1) getEquipmentsByNumber(number)
{ 首先根据“编号”从数据库中获取设备,该数据库具有属性列表,每个属性都有值列表。我遍历这些值(原始对象字符串)以读入变量)
2) getMaterialById(id)
{fetches materials based on id}
2) getMaterialById(id)
{根据id获取材料}
I do understand that the second call, most probably, is making the session to "flush", but I am only 'reading' objects, then why does the second call throws the stale object state exception on the Equipment property if there is nothing changed?
我确实知道第二次调用很可能是使会话“刷新”,但我只是“读取”对象,那么如果没有任何更改,为什么第二次调用会在 Equipment 属性上抛出陈旧的对象状态异常?
I cannot clear the cache after the call since it causes LazyExceptions on objects that I pass to the view.
我无法在调用后清除缓存,因为它会导致传递给视图的对象发生 LazyExceptions。
I have read this: https://forums.hibernate.org/viewtopic.php?f=1&t=996355&start=0but could not solve the problem based on the suggestions provided.
我读过这个:https: //forums.hibernate.org/viewtopic.php?f=1&t=996355&start=0但无法根据提供的建议解决问题。
How can I solve this issue? Any ideas and thoughts are appreciated.
我该如何解决这个问题?任何想法和想法表示赞赏。
UPDATE:What I just tested is that in the function getEquipmentsByNumber()
after reading the variables from list of properties, I do this: getHibernateTemplate().flush();
and now the exception is on this line rather then the call to fetch material (that is getMaterialById(id)
).
更新:我刚刚测试的是,在getEquipmentsByNumber()
从属性列表中读取变量后的函数中,我这样做了:getHibernateTemplate().flush();
现在异常出现在这一行上,而不是调用获取材料(即getMaterialById(id)
)。
UPDATE:Before explicitly calling flush, I am removing the object from session cache so that no stale object remains in the cache.
更新:在显式调用flush之前,我正在从会话缓存中删除对象,以便缓存中没有陈旧的对象。
getHibernateTemplate().evict(equipment);
getHibernateTemplate().flush();
OK, so now the problem has moved to the next fetch from DB after I did this. I suppose I have to label the methods as synchronized and evict the Objects as soon as I am finished reading their contents! it doesn't sound very good.
好的,所以现在问题已经转移到我这样做后从数据库中提取的下一个。我想我必须在阅读完对象的内容后立即将方法标记为同步并驱逐对象!听起来不太好。
UPDATE:Made the handleRequestInternal
method "synchronized". The error disappeared. Ofcourse, not the best solution, but what to do!
Tried in handleRequestInternal
to close the current session and open a new one. But it would cause other parts of the app not to work properly. Tried to use ThreadLocal
that did not work either.
更新:使handleRequestInternal
方法“同步”。错误消失了。当然,不是最好的解决办法,而是怎么办!尝试handleRequestInternal
关闭当前会话并打开一个新会话。但这会导致应用程序的其他部分无法正常工作。尝试使用ThreadLocal
它也不起作用。
回答by walnutmon
This problem was something that I had experienced and was quite frustrating, although there has to be something a little odd going on in your DAO/Hibernate calls, because if you're doing a lookup by ID there is no reason to get a stale state, since that is just a simple lookup for an object.
这个问题是我遇到过的并且非常令人沮丧的事情,尽管在您的 DAO/Hibernate 调用中肯定会发生一些奇怪的事情,因为如果您通过 ID 进行查找,则没有理由获得过时的状态,因为这只是一个简单的对象查找。
First, make sure all your methods are annotated with @Transaction(required=true) // you'll have to look up the exact syntax
首先,确保您的所有方法都带有注释 @Transaction(required=true) // you'll have to look up the exact syntax
However, this exception is usually thrown when you try to make changes to an object that has been detached from the session it was retrieved from. The solution to this is often not simple and would require more code posted so we can see exactly what is going on; my general suggestion would be to create a @Service
that performs these kinds of things within a single transaction
但是,当您尝试更改已与从中检索它的会话分离的对象时,通常会引发此异常。对此的解决方案通常并不简单,需要发布更多代码,以便我们可以准确了解发生了什么;我的一般建议是创建一个@Service
在单个事务中执行这些类型的事情
回答by Puspendu Banerjee
Here are 3 possibilities (as I do not know exactly, which kind of hibernate session handling you are using). Add one after another and test:
这里有 3 种可能性(因为我不确切知道您正在使用哪种休眠会话处理)。一个接一个地添加并测试:
Use bi-directional mapping with inverse=true
between parent object and child object, so the change in parent or child will get propagate to the other end of relation properly.
inverse=true
在父对象和子对象之间使用双向映射,因此父对象或子对象的变化将正确传播到关系的另一端。
Add support for Optimistic Lockingusing TimeStamp
or Version
column
使用或列添加对乐观锁定的支持TimeStamp
Version
Use join queryto fetch the whole object graph [ parent+children] together to avoid the second call altogether.
使用连接查询将整个对象图 [parent+children] 一起获取,以避免完全第二次调用。
Lastly, if and only if nothing works:Load the parent again by Id
(you have that already) and populate modified data then update.
最后,当且仅当没有任何效果时:再次加载父级Id
(您已经有了)并填充修改后的数据然后更新。
Life will be good! :)
生活会很美好!:)
回答by barclay
I also have been struggling with this exception, but when it continued to recur even when I put a lock on the object (and in a test environment, where I knew I was the only process touching the object), I decided to give the parenthetical in the stack trace its due consideration.
我也一直在为这个异常苦苦挣扎,但是当即使我锁定对象时它仍然继续出现时(并且在测试环境中,我知道我是唯一接触该对象的进程),我决定给出括号在堆栈中跟踪其应有的考虑。
org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect): [com.rc.model.mexp.MerchantAccount#59132]
org.hibernate.StaleObjectStateException:行已被另一个事务更新或删除(或未保存的值映射不正确):[com.rc.model.mexp.MerchantAccount#59132]
In our case it turned out that the mapping was wrong; we had type="text"
in the mapping for one field that was a mediumtext type in the database, and it seems that Hibernate really hates that, at least under certain circumstances. We removed the type specification altogether from the mapping for this field, and the problem was resolved.
在我们的例子中,结果证明映射是错误的;我们有type="text"
一个字段的映射,它是数据库中的一种媒体文本类型,而且 Hibernate 似乎真的讨厌这种情况,至少在某些情况下是这样。我们从该字段的映射中完全删除了类型规范,问题得到了解决。
Now the weird thing is that in our production environment, with the supposedly problematic mapping in place, we do NOT get this exception. Does anybody have any idea why this might be? We are using the same version of MySQL - "5.0.22-log" (I don't know what the "-log" means) - in dev and production envs.
现在奇怪的是,在我们的生产环境中,假设有问题的映射到位,我们没有得到这个异常。有人知道为什么会这样吗?我们在开发和生产环境中使用相同版本的 MySQL - “5.0.22-log”(我不知道“-log”是什么意思)。
回答by Thomas W
You're mis-using Hibernate in some way that causes it to think you're updatingor deletingobjects from the database.
您以某种方式误用了 Hibernate,导致它认为您正在更新或删除数据库中的对象。
That's why calling flush()
is throwing an exception.
这就是调用flush()
抛出异常的原因。
One possibility: you're incorrectly "sharing" Session or Entities, via member field(s) of your servlet or controller. This is the main reason 'synchronized' would change your error symptoms.. Short solution: don't ever do this. Sessions and Entities shouldn't & don't work this way -- each Request should get processed independently.
一种可能性: 您通过 servlet 或 controller 的成员字段错误地“共享” Session 或 Entities。这是“同步”会改变您的错误症状的主要原因.. 简短的解决方案:永远不要这样做。会话和实体不应该也不应该以这种方式工作——每个请求都应该独立处理。
Another possibility: unsaved-value
defaults to 0 for "int" PK fields. You may be able to type these as "Integer" instead, if you really want to use 0 as a valid PK value.
另一种可能性: unsaved-value
对于“int” PK fields ,默认为 0。如果您真的想使用 0 作为有效的 PK 值,您可以将它们键入为“整数”。
Third suggestion: use Hibernate Session explicitly, learn to write simple correct code that works, then load the Java source for Hibernate/ Spring libraries so you can read & understand what these libraries are actually doing for you.
第三个建议: 明确使用 Hibernate Session,学习编写简单且正确的代码,然后加载 Hibernate/Spring 库的 Java 源代码,以便您可以阅读和理解这些库实际上为您做什么。