OpenJPA vs Hibernate:EntityManager.merge之间的显着差异

时间:2013-02-04 19:24:29

标签: hibernate jpa merge openjpa entitymanager

因此,我发现OpenJPA(2.1.1)和Hibernate(3.3.1)与EntityManager.merge之间的行为存在重大差异。考虑以下课程:

@Entity(name = "ChoiceHolder")
@Table(name = "CHOICEHOLDER")
@Inheritance(strategy = InheritanceType.JOINED)
public class ChoiceHolder
    implements Equals, HashCode
{

    protected int id;
    protected String choice3;
    protected String choice4;

    @Id
    @Column(name = "ID", scale = 0)
    public int getId() {
        return id;
    }

    public void setId(int value) {
        this.id = value;
    }

    @Basic
    @Column(name = "CHOICE3", length = 255)
    public String getChoice3() {
        return choice3;
    }

    public void setChoice3(String value) {
        this.choice3 = value;
    }

    @Basic
    @Column(name = "CHOICE4", length = 255)
    public String getChoice4() {
        return choice4;
    }
}

并考虑以下客户端代码(这只是一个SSCCE - 在我的实际用例中,两个使用相同ID合并的调用反映了来自两个单独客户端操作的接收数据,其中id之间的目标是相同的两个操作):

ChoiceHolder holder1a = new ChoiceHolder();
holder1a.setId(1);
holder1a.setChoice3("foo");
ChoiceHolder holder1b = new ChoiceHolder();
holder1b.setId(1);
holder1b.setChoice4("bar");

EntityManager em1 = factory.createEntityManager();
em1.merge(holder1a);
em1.close();
EntityManager em2 = factory.createEntityManager();
em2.merge(holder1b);
em2.close();
EntityManager em1Find = factory.createEntityManager();
ChoiceHolder holder1result = em1Find.find(ChoiceHolder.class, 1);
em1find.close();

ChoiceHolder holder2a = new ChoiceHolder();
holder2a.setId(2);
holder2a.setChoice3("foo2");
ChoiceHolder holder2b = new ChoiceHolder();
holder2b.setId(2);
holder2b.setChoice4("bar2");

EntityManager em3 = factory.createEntityManager();
em3.merge(holder2a);
em3.merge(holder2b);
em3.close();
EntityManager em2Find = factory.createEntityManager();
ChoiceHolder holder2result = em2Find.find(ChoiceHolder.class, 2);
em2Find.close();

当我使用Hibernate运行上面的代码时,holder1result对于choice3为null,对于choice4为“bar”。同样,holder2result对于choice3为null,对于choice4为“bar2”。但是,当我使用openJPA运行相同的代码时,我得到了一些非常不同的东西:holder1result同时设置了choice3和choice4,并且使用ReportingSQLException调用了em3.merge(holder2b),因为它试图插入INSERT确实违反了选择者ID的主键约束。

如果重要,这里是我用来配置Hibernate的属性文件中的相关位:

hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect
hibernate.connection.driver_class=org.postgresql.Driver
hibernate.hbm2ddl.auto=create-drop
hibernate.cache.provider_class=org.hibernate.cache.HashtableCacheProvider
hibernate.jdbc.batch_size=0

这是我的persistence.xml中用于配置openJPA的相应位:

<property name="openjpa.jdbc.SynchronizeMappings" value="buildSchema"/>
<property name="openjpa.jdbc.DBDictionary" value="postgres"/>
<property name="openjpa.ConnectionDriverName" value="org.postgresql.Driver"/>
<property name="openjpa.jdbc.MappingDefaults" value="DeferConstraints=true,ForeignKeyDeleteAction=restrict,JoinForeignKeyDeleteAction=restrict"/>

在我的特定情况下,我想要的是我在Hibernate中看到的行为;但是,我的环境(在Karaf内部)需要使用OpenJPA。我可以在OpenJPA上设置标志来改变其行为以匹配我正在寻找的行为吗?

这是对JPA的可怕滥用,如果是这样,我应该使用其他一些技巧/序列的电话吗?

提前致谢!

1 个答案:

答案 0 :(得分:2)

好吧,我想出了一些部分答案 - 但我不确定是否有任何需要关注的副作用。

对于问题#1,choice3未正确排除,我必须在persistence.xml文件中将openjpa.DetachState设置为all

对于问题#2,在EntityManager.flush的调用之间添加对merge的调用可解决问题。奇怪的是,在第一次调用merge之前添加调用也解决了问题,这导致我怀疑flush正在EntityManager上设置一些状态,但我不确定为什么会这样。