Java Hibernate:merge() 比 update() 的缺点

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2118257/
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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-13 03:43:29  来源:igfitidea点击:

Hibernate : Downside of merge() over update()

javahibernatesession

提问by Marty Pitt

I'm having problems with a NonUniqueObjectExceptionthrown by Hibernate.

我遇到了NonUniqueObjectExceptionHibernate 抛出的问题。

Reading the docs, and thisblog post, I replaced the call from update()to merge(), and it solved the problem.

阅读文档和这篇博文,我将调用替换为update()to merge(),它解决了问题。

I believe I understand the reason for the exception, and why changing the method fixed the problem, in terms of disconnected objects and session boundaries.

我相信我理解异常的原因,以及为什么更改方法可以解决断开连接的对象和会话边界方面的问题。

My question is : given that merge()will always resolve to the session object, or retrieve it if it doesn't exist, is calling merge() generally a safer alternative than update()?

我的问题是:鉴于它merge()总是会解析为会话对象,或者如果它不存在则检索它,那么调用 merge() 通常比update()?

What is the downside of using merge()over update()?

使用merge()over的缺点是update()什么?

采纳答案by Arthur Ronald

Is calling merge() generally a safer alternative than update() ?

调用 merge() 通常比 update() 更安全吗?

As a way to avoid NonUniqueObjectException, yes. I think it explains why JPA does not allow an update method.

作为避免 NonUniqueObjectException 的一种方式,是的。我认为它解释了为什么 JPA 不允许更新方法。

What is the downside of using merge() over update() ?

使用 merge() 而不是 update() 的缺点是什么?

An unadvised user may think he or she has a fresh managed entity. Something like

一个不知情的用户可能认为他或她有一个新的托管实体。就像是

// myEntity (passed as parameter does not become managed)
// Only the one returned by the merge operation is a managed entity
session.merge(myEntity);

// "newValue" is not commited because myEntity is not managed
myEntity.setMyProperty("newValue");

And if your persistence context does not contain your entity, maybe you do not want select-before-updatingdefault behavior. But it can be avoided

如果您的持久性上下文不包含您的实体,那么可能不希望更新前选择默认行为。但是可以避免

  • Add a version (@Version) column. 0 or NULL version indicates that an instance is newand has to be inserted, not updated
  • Use a Hibernate interceptor
  • If you are sure you want to update instead of inserting, you can use the following approach
  • 添加版本 (@Version) 列。0 或 NULL 版本表示实例是新的,必须插入,而不是更新
  • 使用 Hibernate 拦截器
  • 如果您确定要更新而不是插入,则可以使用以下方法

...

...

public void updateMyEntity(MyEntity updateableMyEntity);

    // load does not hit the database
    MyEntity myEntity = (MyEntity) session.load(MyEntity.class, updateableMyEntity.getId());

    BeanUtils.copyProperties(myEntity, updateableMyEntity);

}

This way you can update your entity without merge or update method. See this question for more information: Best way to update some fields of a detached object on Hibernate ?

这样您就可以在没有合并或更新方法的情况下更新您的实体。有关更多信息,请参阅此问题:Best way to update some fields of a detached object on Hibernate ?

回答by Mark R

Use update() if you are sure that the session does not contain an already persistent instance with the same identifier and merge() if you want to merge your modifications at any time without consideration of the state of the session. In other words update() is usually the first method you would call in a fresh session ensuring that reattachment of your detached instances is the first operation that is executed.

如果您确定会话不包含具有相同标识符的已持久实例,请使用 update(),如果您想在不考虑会话状态的情况下随时合并修改,请使用 merge()。换句话说,update() 通常是您在新会话中调用的第一个方法,以确保重新附加分离的实例是执行的第一个操作。

回答by Ajit Deswal

SessionFactory factory = cfg.buildSessionFactory();

Session session1 = factory.openSession();
Student s1 = null;
Object o = session1.get(Student.class, new Integer(101));
s1 = (Student)o;
session1.close();
s1.setMarks(97);

Session session2 = factory.openSession();
Student s2 = null;
Object o1 = session2.get(Student.class, new Integer(101));
s2 = (Student)o1;

Transaction tx=session2.beginTransaction();
session2.merge(s1);

Explanation

解释

See from line numbers 4–7, we just loaded one object s1 into session1 cache and closed session1 at line number 7, so now object s1 in the session1 cache will be destroyed as session1 cache will expires when ever we say session1.close().

从第 4-7 行看,我们刚刚将一个对象 s1 加载到 session1 缓存中并在第 7 行关闭 session1,所以现在 session1 缓存中的对象 s1 将被销毁,因为 session1 缓存将在我们说 时过期session1.close()

Now s1 object will be in some RAM location, not in the session1 cache. Here s1 is in detached state, and at line number 8 we modified that detached object s1, now if we call update()method then hibernate will throws an error, because we can update the object in the session only.

现在 s1 对象将位于某个 RAM 位置,而不是 session1 缓存中。这里 s1 处于分离状态,并且在第 8 行我们修改了分离的对象 s1,现在如果我们调用update()方法然后 hibernate 将抛出错误,因为我们只能在会话中更新对象。

So we opened another session [session2] at line number 10, and again loaded the same student object from the database, but with name s2. So in this session2, we called session2.merge(s1);now into s2 object s1 changes will be merged and saved into the database

因此,我们在第 10 行打开了另一个会话 [session2],并再次从数据库中加载了相同的学生对象,但名称为 s2。所以在这个 session2 中,我们调用session2.merge(s1);now into s2 对象 s1 的变化会被合并并保存到数据库中