Java 休眠错误:具有相同标识符值的不同对象已与会话相关联
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/16246675/
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
Hibernate Error: a different object with the same identifier value was already associated with the session
提问by John
I essentially have some objects in this configuration (the real data model is a bit more complex):
我基本上在这个配置中有一些对象(真实的数据模型有点复杂):
- A has a many-to-many relationship with B. (B has
inverse="true"
) - B has a many-to-one relationship with C. (I have
cascade
set to"save-update"
) - C is a kind of type/category table.
- A 与 B 存在多对多关系。 (B has
inverse="true"
) - B 和 C 是多对一的关系。(我已经
cascade
设置为"save-update"
) - C 是一种类型/类别表。
Also, I should probably mention that the primary keys are generated by the database on save.
另外,我可能应该提到主键是由数据库在保存时生成的。
With my data, I sometimes run into problems where A has a set of different B objects, and these B objects refer to the same C object.
对于我的数据,我有时会遇到一些问题,其中 A 有一组不同的 B 对象,而这些 B 对象引用同一个 C 对象。
When I call session.saveOrUpdate(myAObject)
, I get a hibernate error saying: "a different object with the same identifier value was already associated with the session: C"
. I know that hibernate can't insert/update/delete the same object twice in the same session, but is there some way around this? This doesn't seem like it would be that uncommon of a situation.
当我打电话时session.saveOrUpdate(myAObject)
,我收到一个休眠错误说:"a different object with the same identifier value was already associated with the session: C"
。我知道 hibernate 不能在同一个会话中两次插入/更新/删除同一个对象,但是有什么办法可以解决这个问题吗?这种情况似乎并不罕见。
During my research of this problem, I have seen folks suggest the use of session.merge()
, but when I do that, any "conflicting" objects get inserted into the database as blank objects with all values set to null. Clearly that isn't what we want.
在我研究这个问题的过程中,我看到有人建议使用session.merge()
,但是当我这样做时,任何“冲突”对象都会作为空白对象插入到数据库中,所有值都设置为空。显然这不是我们想要的。
[Edit] Another thing I forgot to mention is that (for architectural reasons beyond my control), each read or write needs to be done in a separate session.
[编辑] 我忘记提及的另一件事是(出于我无法控制的架构原因),每次读取或写入都需要在单独的会话中完成。
采纳答案by jbx
Most probably its because the B objects are not referring to the same Java C object instance. They are referring to the same row in the database (i.e. the same primary key) but they're different copies of it.
很可能是因为 B 对象不是指同一个 Java C 对象实例。它们指的是数据库中的同一行(即相同的主键),但它们是它的不同副本。
So what is happening is that the Hibernate session, which is managing the entities would be keeping track of which Java object corresponds to the row with the same primary key.
因此,正在发生的事情是管理实体的 Hibernate 会话将跟踪哪个 Java 对象对应于具有相同主键的行。
One option would be to make sure that the Entities of objects B that refer to the same row are actually referring to the same object instance of C. Alternatively turn off cascading for that member variable. This way when B is persisted C is not. You will have to save C manually separately though. If C is a type/category table, then it probably makes sense to be that way.
一种选择是确保引用同一行的对象 B 的实体实际上引用 C 的同一对象实例。或者关闭该成员变量的级联。这样当 B 被持久化时 C 不是。不过,您必须单独手动保存 C。如果 C 是一个类型/类别表,那么这样做可能是有意义的。
回答by Fawad Khaliq
you might not be setting the identifier of the object before calling update query.
在调用更新查询之前,您可能没有设置对象的标识符。
回答by Ales Potocnik Hahonina
Just came across this message but in c# code. Not sure if it's relevant (exactly the same error message though).
刚刚遇到此消息,但在 c# 代码中。不确定它是否相关(尽管完全相同的错误消息)。
I was debugging the code with breakpoints and expanded some collections through private members while debugger was at a breakpoint. Having re-run the code without digging through structures made the error message go away. It seems like the act of looking into private lazy-loaded collections has made NHibernate load things that were not supposed to be loaded at that time (because they were in private members).
我正在使用断点调试代码,并在调试器处于断点时通过私有成员扩展了一些集合。在没有挖掘结构的情况下重新运行代码使错误消息消失。似乎查看私有延迟加载集合的行为使 NHibernate 加载了当时不应该加载的内容(因为它们在私有成员中)。
The code itself is wrapped in a fairly complicated transaction that can update large number of records and many dependencies as part of that transaction (import process).
代码本身包含在一个相当复杂的事务中,该事务可以更新大量记录和许多依赖项,作为该事务(导入过程)的一部分。
Hopefully a clue to anyone else who comes across the issue.
希望对遇到此问题的其他人有所帮助。
回答by user2845946
Transfer the task of assigning the object ID from Hibernate to the database by using:
使用以下命令将分配对象 ID 的任务从 Hibernate 转移到数据库:
<generator class="native"/>
This solved the problem for me.
这为我解决了这个问题。
回答by dsk
You only need to do one thing. Run session_object.clear()
and then save the new object. This will clear the session (as aptly named) and remove the offending duplicate object from your session.
你只需要做一件事。运行session_object.clear()
然后保存新对象。这将清除会话(如恰当命名)并从会话中删除有问题的重复对象。
回答by Waqar
One way to solve the above problem will be to override the hashcode()
.
Also flush the hibernate session before and after save.
解决上述问题的一种方法是覆盖hashcode()
.
在保存之前和之后刷新休眠会话。
getHibernateTemplate().flush();
Explicitly setting the detached object to null
also helps.
将分离的对象显式设置为null
也有帮助。
回答by Hemant kumar
Add the annotation @GeneratedValue to the bean you are inserting.
将注释 @GeneratedValue 添加到您要插入的 bean 中。
回答by Buddhi
I had this error few days a go and I sped too many time on fixing this error.
几天前我遇到了这个错误,我花了太多时间来修复这个错误。
public boolean save(OrderHeader header) {
Session session = sessionFactory.openSession();
Transaction transaction = session.beginTransaction();
try {
session.save(header);
for (OrderDetail detail : header.getDetails()) {
session.save(detail);
}
transaction.commit();
session.close();
return true;
} catch (HibernateException exception) {
exception.printStackTrace();
transaction.rollback();
return false;
}
}
Before i get this error , I didn't have mentioned ID generation type on the OrderDetil Object. when without generating Orderdetails' id it keeps Id as 0 for every OrderDetail objects. this what #jbx explained. Yes it is the best answer. this one example how it happens.
在我收到此错误之前,我没有在 OrderDetil 对象上提到 ID 生成类型。当不生成 Orderdetails 的 id 时,它会将每个 OrderDetail 对象的 Id 保持为 0。这就是#jbx 所解释的。是的,这是最好的答案。这个例子是如何发生的。
回答by 4n0y
Just set cascade to MERGE, that should do the trick.
只需将级联设置为 MERGE,就可以解决问题。
回答by Ice Blue
I agree with @Hemant Kumar, thank you very much. According his solution, I solved my problem.
我同意@Hemant Kumar,非常感谢。根据他的解决方案,我解决了我的问题。
For example:
例如:
@Test
public void testSavePerson() {
try (Session session = sessionFactory.openSession()) {
Transaction tx = session.beginTransaction();
Person person1 = new Person();
Person person2 = new Person();
person1.setName("222");
person2.setName("111");
session.save(person1);
session.save(person2);
tx.commit();
}
}
Person.java
人.java
public class Person {
private int id;
private String name;
@Id
@Column(name = "id")
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
@Basic
@Column(name = "name")
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
This code always make mistake in my application:
A different object with the same identifier value was already associated with the session
, later I found out that I forgot
to autoincrease my primary key!
这段代码在我的应用程序中总是出错:
A different object with the same identifier value was already associated with the session
,后来我发现我忘记自动增加我的主键了!
My solution is to add this code on your primary key:
我的解决方案是在您的主键上添加此代码:
@GeneratedValue(strategy = GenerationType.AUTO)