为什么我可以在具有相同id的相同持久化上下文中有两个实体

时间:2013-11-24 19:26:18

标签: jpa

public void whyEntityExistsExceptionisnotthrown(){
    EntityManager em=getEntityManager();
    try{
        Partner partnerOne=em.find(Partner.class, 1L); // from the database
        System.out.println("Partner partnerOne  information-----------> "+partnerOne.getName());
        Partner partnerTwo =new Partner();
        partnerTwo.setIdpartner(1L);
        partnerTwo.setName("Partner 200");
        em.persist(partnerTwo);         
        Partner partnerThree=em.find(Partner.class, 1L);
        // the method find has two entities with the id 1L. I think this could be a problem.            
        if(em.contains(partnerOne))
                System.out.println("PartnerOne managed");
        if(em.contains(partnerTwo))
            System.out.println("PartnerTwo managed");

        System.out.println("Partner partnerTwo  information-----------> "+partnerTwo.getName());
        System.out.println("Partner partnerThree  information-----------> "+partnerThree.getName());

    }catch(EntityExistsException e){
            System.out.println("The entity already exist");
    }
}

通过这篇文章,我试图通过允许两个实体在持久化上下文中具有相同的id来发现问题。 问题是: 有没有办法避免在调用flush方法或提交之前在持久化上下文中有两个具有相同id的托管实体? 为什么不抛出异常?

如果我调用此方法,结果是:

首先调用whyEntityExistsExceptionisnotthrown partnerOne:来自数据库的信息(我在id = 1的数据库中有一个合作伙伴) partnerTwo:Name = Partner 200 partnerThree:Name = Partner 200(但可能是partnerOne的信息。

下一个电话         partnerOne ------>名称=合作伙伴200     partnerTwo ------>名称=合作伙伴200         partnerThree ---->名称=合作伙伴200

1 个答案:

答案 0 :(得分:0)

根据persist()方法的文档,它会抛出

  

EntityExistsException - 如果实体已存在。 (如果是实体   已存在,可能会抛出EntityExistsException   调用persist操作,或EntityExistsException 或其他   在刷新或提交时可能会抛出PersistenceException 。)

因此,为了确保您的persist()到达数据库,您应该在保留实体后立即调用em.flush(),然后您将获得一个异常(调用{时出现EntityExistsException) {1}}或EntityExistsException / PersistenceException persist)。是的,有人可能会问自己为什么JPA规范在这一点上不是很清楚,但我很确定有充分的理由,比如性能(尝试对DB进行单个I / O操作)。因此,如果您需要可移植/工作代码,请调用flush操作。您可能不明白,在事务提交之前,大多数操作(例如flush()removemerge都无法保证到达DB。因此,您有责任在需要时致电persist

回答您的问题:

  

有没有办法避免可能有两个托管实体   在调用flush方法之前,持久化上下文中的相同id   还是提交?

我对此表示怀疑,而且到目前为止我还没有发现需要(!调用flush!)。据我所知,JPA规范。不需要。

  

为什么不抛出异常?

因为在那一刻不能保证flush()与DB同步。文档说得很清楚。

一些重要说明: 据我所知,您的ID字段不会自动生成。通常,应用程序允许DB生成ID,以便调用persist与DB同步。

此外,在您的代码中(未经测试)我确信persist被评估为true,这意味着它们实际上是完全相同的对象。唯一的问题是partnerOne==partnerThree,你必须冲洗。