两次合并同一实体会导致INSERT-Primary Key违规

时间:2015-09-03 09:04:19

标签: java jpa openjpa

我有一个非常简单的JAP-Entity,没有任何其他类的链接:

@Entity
@IdClass(TimestampNameAndGroupIdentity.class)
public class TechFitMainClassHistory extends JPABase {

    @Id
    @Basic
    protected Date timestamp;

    @Id
    @Basic
    protected String type_name;

    @Id
    @Basic
    protected String group_name;

    @Basic
    protected int count;

    ...

与IdClass:

public class TimestampNameAndGroupIdentity implements Serializable {
    private static final long serialVersionUID = 1L;

    public Date timestamp;
    public String type_name;
    public String group_name;

    ...

在测试中,我尝试将其合并两次:

        em.merge(new TechFitMainClassHistory(date, "com.test.Main", "java", 2));
        em.merge(new TechFitMainClassHistory(date, "com.test.Main", "java", 2));

我收到以下错误

Caused by: org.apache.openjpa.lib.jdbc.ReportingSQLException: Violation of PRIMARY KEY constraint 'PK__TechFitM__D91CE761E4A3725C'. Cannot insert duplicate key in object 'dbo.TechFitMainClassHistory'. The duplicate key value is (PROCESS_TYPE_MAIN, 2015-09-03 00:00:00.0000000, com.ruxit.Main). {prepstmnt 261650860 INSERT INTO TechFitMainClassHistory (group_name, timestamp, type_name, count) VALUES (?, ?, ?, ?)} [code=2627, state=23000]
    at org.apache.openjpa.lib.jdbc.LoggingConnectionDecorator.wrap(LoggingConnectionDecorator.java:219)
    at org.apache.openjpa.lib.jdbc.LoggingConnectionDecorator.wrap(LoggingConnectionDecorator.java:207)
    at org.apache.openjpa.lib.jdbc.LoggingConnectionDecorator.access$1200(LoggingConnectionDecorator.java:59)
    at org.apache.openjpa.lib.jdbc.LoggingConnectionDecorator$LoggingConnection$LoggingPreparedStatement.executeBatch(LoggingConnectionDecorator.java:1215)
    at org.apache.openjpa.lib.jdbc.DelegatingPreparedStatement.executeBatch(DelegatingPreparedStatement.java:250)
    at org.apache.openjpa.jdbc.kernel.JDBCStoreManager$CancelPreparedStatement.executeBatch(JDBCStoreManager.java:1810)
    at org.apache.openjpa.jdbc.kernel.BatchingPreparedStatementManagerImpl.executeBatch(BatchingPreparedStatementManagerImpl.java:364)
    at org.apache.openjpa.jdbc.kernel.BatchingPreparedStatementManagerImpl.flushBatch(BatchingPreparedStatementManagerImpl.java:189)
    ... 39 more

有两种情况没有出现错误: *如果我在电话之间提交 *如果在调用之前对象已存在

这只是简化的测试用例,实际的应用程序做了类似的事情,我希望根据merge()方法的描述来工作。

那么为什么我会收到此错误?我希望合并多次工作,或者这是OpenJPA中的错误/限制?

1 个答案:

答案 0 :(得分:0)

合并的预期行为是:

  • 在持久化上下文中查找具有相同ID的附加对象。
  • 如果存在更新并返回已经附加的对象(并让给定的对象不受管理)。
  • 如果没有,请复制,保留(附加)并返回(并让给定的原始实例不受管理)......

因此,您在测试用例中所期望的行为应该有效,除非两个合并调用都不是在相同的持久化上下文中进行的(两次调用之间的提交修复了您的错误导致认为是这种情况)

然而,在并发上下文中,您将重现此问题,因为两个实体都属于两个不同的等级持久化上下文,第二个要刷新将触发pk违规