尝试保存代表同一实体的不同java对象。过冬

时间:2015-08-11 21:29:36

标签: java hibernate identity

(这是对实际问题的简化)

让我们从以下小课程开始:

@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();

什么?如何将对象放在不同的内存位置可能是相关的?不知怎的,代码抛出异常。

如何让第二个例子像第一个一样工作?

3 个答案:

答案 0 :(得分:1)

我只是重写了@ jb-nizet在评论中所写的内容,感觉就像我的回答:

  

Hibernate不使用==。它只是做你要告诉它的事情。   persist的契约是:将此对象与会话相关联。如果它是   已经与会话相关联,这是一个noop。如果不是,那就是   与稍后要插入数据库的会话相关联。如果   你想要做的是确保复制该对象的状态   一个持久的实体,然后给我那个持久的实体   你正在寻找合并()。

所以解决方案就是使用

AtheManager.merge(obj1);

而不是

AtheManager.persist(obj1);

答案 1 :(得分:0)

在第一种情况下,您将同一对象保存两次,这是允许的。 但在第二种情况下,您将两个不同的对象保存到数据库,但两者都具有相同的主键。它是数据库约束违规。

答案 2 :(得分:0)

在第一个示例中,您传递对象的引用以保存它,并在第二个调用中传递完全相同的引用;它们都指向内存中的同一个对象。

但是,在第二个示例中,您分配了两个具有两个新调用的对象,这两个调用在两个不同的内存地址创建对象;它们是两个不同的对象。第一个引用指向其他一些内存地址,然后指向第二个对象的引用。如果你在第二个例子中尝试过这个,它将返回false:obj1 == obj1 _