Hibernate错误:具有相同标识符值的不同对象已与会话关联

Joh*_*ohn 79 java hibernate

我在这个配置中基本上有一些对象(真正的数据模型有点复杂):

  • A与B有多对多的关系.(B有inverse="true")
  • B与C有多对一的关系.(我已经cascade设定"save-update")
  • C是一种类型/类别表.

另外,我应该提一下主键是在保存时由数据库生成的.

对于我的数据,我有时会遇到A有一组不同B对象的问题,这些B对象引用相同的C对象.

当我打电话时session.saveOrUpdate(myAObject),我得到一个休眠错误说:"a different object with the same identifier value was already associated with the session: C".我知道hibernate不能在同一个会话中两次插入/更新/删除同一个对象,但有什么方法可以解决这个问题吗?这似乎不是一种不常见的情况.

在我研究这个问题的过程中,我看到人们建议使用session.merge(),但是当我这样做时,任何"冲突"对象都会作为空白对象插入到数据库中,所有值都设置为null.显然,这不是我们想要的.

[编辑]我忘记提到的另一件事是(由于我无法控制的架构原因),每次读取或写入都需要在单独的会话中完成.

jbx*_*jbx 82

很可能是因为B对象不是指同一个Java C对象实例.它们指的是数据库中的同一行(即相同的主键),但它们是它的不同副本.

所以正在发生的事情是管理实体的Hibernate会话将跟踪哪个Java对象对应于具有相同主键的行.

一种选择是确保引用同一行的对象B的实体实际上是指C的同一对象实例.或者关闭该成员变量的级联.这种方式当B持久存在时C不是.您必须单独手动保存C. 如果C是类型/类别表,那么这样做可能是有意义的.

  • 我使用merge()而不是saveOrUpdate()和BOOM!有用 :) (13认同)
  • 谢谢jbx.正如你所说,事实证明B对象是指内存中的多个C实例.基本上发生的事情是我的程序的一部分是在C中读取,并将其附加到B.另一部分是从数据库中加载具有相同C的不同B. 两者都附加到A,在保存时触发错误.我已将B-> C关系的<pre> cascade </ pre>设置为"<pre> none </ pre>",但我仍然遇到同样的错误.在多对一或一对多的关系中,有没有办法告诉Hibernate只更改外键而不用担心其余的? (3认同)

aol*_*awa 22

只需将级联设置为MERGE即可.


dsk*_*dsk 11

你只需要做一件事.运行session_object.clear()然后保存新对象.这将清除会话(如命名),并从会话中删除有问题的重复对象.

  • 如何获取具有“clear()”方法的“session_object”? (4认同)

Ice*_*lue 8

我同意@Hemant Kumar,非常感谢。根据他的解决方案,我解决了我的问题。

例如?

@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();
    }
}
Run Code Online (Sandbox Code Playgroud)

人.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;
    }

}
Run Code Online (Sandbox Code Playgroud)

这段代码在我的应用程序中总是会犯错误: A different object with the same identifier value was already associated with the session,后来我发现我忘了自动增加主键!

我的解决方案是在您的主键上添加以下代码:

@GeneratedValue(strategy = GenerationType.AUTO)
Run Code Online (Sandbox Code Playgroud)


小智 8

这意味着您正在尝试使用对同一对象的引用在表中保存多行。

检查您的实体类的 id 属性。

@Id
private Integer id;
Run Code Online (Sandbox Code Playgroud)

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(unique = true, nullable = false)
private Integer id;
Run Code Online (Sandbox Code Playgroud)


use*_*946 5

使用以下命令将从Hibernate分配对象ID的任务转移到数据库:

<generator class="native"/>
Run Code Online (Sandbox Code Playgroud)

这解决了我的问题.


use*_*037 5

另一种情况是可以自定义生成相同的错误消息allocationSize

@Id
@Column(name = "idpar")
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "paramsSequence")
@SequenceGenerator(name = "paramsSequence", sequenceName = "par_idpar_seq", allocationSize = 20)
private Long id;
Run Code Online (Sandbox Code Playgroud)

不匹配

alter sequence par_idpar_seq increment 20;
Run Code Online (Sandbox Code Playgroud)

可能会在插入期间导致约束验证(这一点很容易理解)或“具有相同标识符值的不同对象已与会话关联” - 这种情况不太明显。