重复的键值违反了主键的唯一约束

时间:2019-06-21 16:25:52

标签: java sql postgresql eclipselink primary-key

我遇到问题duplicate key value violates unique constraint "my_obj_pk"。 其中my_obj_pk是映射到Spring实体并基于id的表的主键:

@Entity
@Table(name = "MY_TABLE")
@SequenceGenerator(name = "MY_OBJ_SEQ", allocationSize = 500)
public class MyObject {

   @Id
   @GeneratedValue(generator = "MY_OBJ_SEQ", strategy = GenerationType.TABLE)
   private Long id;
...
}

例外是:

Internal Exception: java.sql.BatchUpdateException: Batch entry 1 INSERT INTO MY_TABLE (ID, ...) VALUES (257521, ...) was aborted: ERROR: duplicate key value violates unique constraint "my_obj_pk"
  Detail: Key (id)=(257521) already exists.  Call getNextException to see other errors in the batch.
Error Code: 0
Call: INSERT INTO MY_TABLE (ID, ...) VALUES (?, ...)
    bind => [8 parameters bound]
    at org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:524)
    at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:757)
    at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:726)
    at org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:478)
    at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:272)
    at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:95)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:207)
    at com.sun.proxy.$Proxy341.saveMyObject(Unknown Source)
    at MyWorker.doWork(MyWorker.java:172)
    at java.util.concurrent.CompletableFuture$AsyncRun.run$$$capture(CompletableFuture.java:1626)
    ... 4 more
Caused by: javax.persistence.RollbackException: Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.7.3.v20180807-4be1041): org.eclipse.persistence.exceptions.DatabaseException
Internal Exception: java.sql.BatchUpdateException: Batch entry 1 INSERT INTO MY_TABLE (ID, ...) VALUES (257521, ...) was aborted: ERROR: duplicate key value violates unique constraint "my_obj_pk"
  Detail: Key (id)=(257521) already exists.  Call getNextException to see other errors in the batch.
Error Code: 0

您可能会看到JPA实现是Eclipse Persistence Services - 2.7.3.v20180807-4be1041。数据库是PostgreSQl 9.4.0。

MyWorker是一个Spring组件,它每10分钟产生35个CompletableFuture对象,这些对象通过具有20个线程的执行程序运行。每个这样的Future会多次调用 Spring Service MyServiceImpl,其中服务中的每个功能都用TransactionalPermitAll进行注释。这些函数通过RepositoryX这两个不同的Collection<Y>对象来拉取, 如果还不存在,则会创建这些对象的一部分,但是不会显式保存。

X具有以下内容:

@OneToMany(mappedBy = "xObj", fetch = FetchType.LAZY, cascade = CascadeType.REMOVE)
List<MyObject> myObjects;

Y具有以下内容:

@OneToMany(mappedBy = "yObj", fetch = FetchType.LAZY, cascade = CascadeType.REMOVE)
List<MyObject> myObjects;

MyObject具有:

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "X_ID")
private X xObj;

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "Y_ID")
private Y yObj;

因此,基本上,XY的列表中包含MyObjectX的{​​{1}}

最后,每个Y分别从同一Future调用saveMyObject()X的{​​{1}}:

Collection<Y>

在任何地方都没有手动分配ID ... 到目前为止,我还不知道如何复制MyObject的PK。如果可能的话,我宁愿不要触摸MyServiceImpl属性,因为这些类已经存在很长时间了 并且被广泛使用。谢谢!

编辑:我要补充一点,在同一@Override @PermitAll @Transactional public void saveMyObject(X x, Collection<Y> colY) { xRepository.save(x); yRepository.save(colY); final List<MyObject> myObjects = x.getMyObjects() == null ? new ArrayList<>(colY.size()) : x.getMyObjects(); colY.forEach(p -> { MyObject o = new MyObject(); myObjects.add(o); List<MyObject> pobj = p.getMyObjects(); if (pobj == null) { pobj = new ArrayList<>(); p.setMyObjects(pobj); } pobj.add(o); }); x.setMyObjects(myObjects); myObjectsRepository.save(myObjects); } CASCADE上可能使用不同的Future,所以设计可能不太正确

0 个答案:

没有答案