(这是对实际问题的简化)
让我们从以下小课程开始:
@Entity
class Test {
Test(int id, String name) {
this.id = id;
this.name = name;
}
@Id
private int id;
@Column
private String name;
@Override
public int hashCode() {
return id;
}
@Override
public boolean equals(Object obj) {
if (obj instanceof Test) {
return id == ((Test) obj).id;
}
return false;
}
}
如果我们执行以下操作,则不会发生异常:
EntityManagerFactory factory = Persistence.createEntityManagerFactory("local_h2_persistence");
EntityManager theManager = factory.createEntityManager();
EntityTransaction t = theManager.getTransaction();
Test obj1 = new Test(1, "uno");
tA.begin();
AtheManager.persist(obj1);
AtheManager.persist(obj1); // <-- No exception
tA.commit();
我猜第二次调用被忽略,或者对象可能再次保存到DB。事情是两次保存同一个实体没有问题。现在让我们尝试以下方法:
EntityManagerFactory factory = Persistence.createEntityManagerFactory("local_h2_persistence");
EntityManager theManager = factory.createEntityManager();
EntityTransaction t = theManager.getTransaction();
Test obj1 = new Test(1, "uno");
Test obj1_ = new Test(1, "uno");
tA.begin();
AtheManager.persist(obj1);
AtheManager.persist(obj1_); // <-- javax.persistence.EntityExistsException: a different object with the same identifier value was already associated with the session
tA.commit();
什么?如何将对象放在不同的内存位置可能是相关的?不知怎的,代码抛出异常。
如何让第二个例子像第一个一样工作?
答案 0 :(得分:1)
我只是重写了@ jb-nizet在评论中所写的内容,感觉就像我的回答:
Hibernate不使用==。它只是做你要告诉它的事情。 persist的契约是:将此对象与会话相关联。如果它是 已经与会话相关联,这是一个noop。如果不是,那就是 与稍后要插入数据库的会话相关联。如果 你想要做的是确保复制该对象的状态 一个持久的实体,然后给我那个持久的实体 你正在寻找合并()。
所以解决方案就是使用
AtheManager.merge(obj1);
而不是
AtheManager.persist(obj1);
答案 1 :(得分:0)
在第一种情况下,您将同一对象保存两次,这是允许的。 但在第二种情况下,您将两个不同的对象保存到数据库,但两者都具有相同的主键。它是数据库约束违规。
答案 2 :(得分:0)
在第一个示例中,您传递对象的引用以保存它,并在第二个调用中传递完全相同的引用;它们都指向内存中的同一个对象。
但是,在第二个示例中,您分配了两个具有两个新调用的对象,这两个调用在两个不同的内存地址创建对象;它们是两个不同的对象。第一个引用指向其他一些内存地址,然后指向第二个对象的引用。如果你在第二个例子中尝试过这个,它将返回false:obj1 == obj1 _