Java JPA和多线程合并生成异常id已存在

Java JPA和多线程合并生成异常id已存在,java,multithreading,postgresql,jpa,Java,Multithreading,Postgresql,Jpa,我有一个实体,其中id字段被描述为: @Id @Column(name = "id", unique = true, nullable = false, insertable = true, updatable = true) @SequenceGenerator(name = "records_id_seq", sequenceName = "records_id_seq", schema = "recorder", initialValue = 1, allocationSize = 1)

我有一个实体,其中id字段被描述为:

@Id
@Column(name = "id", unique = true, nullable = false, insertable = true, updatable = true)
@SequenceGenerator(name = "records_id_seq", sequenceName = "records_id_seq", schema = "recorder", initialValue = 1, allocationSize = 1)
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "records_id_seq")
private Long id;
当多线程尝试插入新数据时,似乎出现了一个问题,因为我的应用程序希望插入两个具有相同id值的实体,而我的数据库拒绝了这两个实体,因为id是唯一的

应该做些什么来防止这种情况

在哪里可以告诉我的实体不要尝试插入id值,让数据库在插入阶段自己生成id值

谢谢你的帮助

编辑:例外:

11:17:47.407 ERROR - Uncatched exception at 201507091117 for thread Thread[RecorderBase-Pool-Thread-1,5,RMI Runtime] : 
javax.persistence.RollbackException: Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.6.0.v20140809-296a69f): org.eclipse.persistence.exceptions.DatabaseException
Internal Exception: org.postgresql.util.PSQLException: ERROR: duplicate key value violates unique constraint "pkey_records_id"
  Détail : Key (id)=(280) already exists.
Error Code: 0
Call: INSERT INTO recorder.records (id, name, number, DELETED, frid, frname, end, start, hid, REFERENCE, toid, toname) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
    bind => [12 parameters bound]
Query: InsertObjectQuery(Record[280/20014364334653801])
    at org.eclipse.persistence.internal.jpa.transaction.EntityTransactionImpl.commit(EntityTransactionImpl.java:159) ~[ModuleA-2.1.0.jar:na]
    at DBHelper.save(DBHelper.java:215) ~[ModuleA-2.1.0.jar:na]
    at DBHelper.save(DBHelper.java:230) ~[ModuleA-2.1.0.jar:na]
    at RecordEngine$1.run(RecordEngine.java:253) ~[ModuleA-2.1.0.jar:na]
    at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source) ~[na:1.8.0_40]
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source) ~[na:1.8.0_40]
    at java.lang.Thread.run(Unknown Source) ~[na:1.8.0_40]
Caused by: org.eclipse.persistence.exceptions.DatabaseException: 
Internal Exception: org.postgresql.util.PSQLException: ERROR: duplicate key value violates unique constraint "pkey_records_id"
  Détail : Key (id)=(280) already exists.
Error Code: 0
Call: INSERT INTO recorder.records (id, name, number, DELETED, frid, frname, end, start, hid, REFERENCE, toid, toname) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
    bind => [12 parameters bound]
Query: InsertObjectQuery(Record[280/20014364334653801])
    at org.eclipse.persistence.exceptions.DatabaseException.sqlException(DatabaseException.java:340) ~[ModuleA-2.1.0.jar:na]
    at org.eclipse.persistence.internal.databaseaccess.DatabaseAccessor.processExceptionForCommError(DatabaseAccessor.java:1611) ~[ModuleA-2.1.0.jar:na]
    at org.eclipse.persistence.internal.databaseaccess.DatabaseAccessor.executeDirectNoSelect(DatabaseAccessor.java:898) ~[ModuleA-2.1.0.jar:na]
    at org.eclipse.persistence.internal.databaseaccess.DatabaseAccessor.executeNoSelect(DatabaseAccessor.java:962) ~[ModuleA-2.1.0.jar:na]
    at org.eclipse.persistence.internal.databaseaccess.DatabaseAccessor.basicExecuteCall(DatabaseAccessor.java:631) ~[ModuleA-2.1.0.jar:na]
    at org.eclipse.persistence.internal.databaseaccess.DatabaseAccessor.executeCall(DatabaseAccessor.java:558) ~[ModuleA-2.1.0.jar:na]
    at org.eclipse.persistence.internal.sessions.AbstractSession.basicExecuteCall(AbstractSession.java:2000) ~[ModuleA-2.1.0.jar:na]
    at org.eclipse.persistence.sessions.server.ClientSession.executeCall(ClientSession.java:298) ~[ModuleA-2.1.0.jar:na]
    at org.eclipse.persistence.internal.queries.DatasourceCallQueryMechanism.executeCall(DatasourceCallQueryMechanism.java:242) ~[ModuleA-2.1.0.jar:na]
    at org.eclipse.persistence.internal.queries.DatasourceCallQueryMechanism.executeCall(DatasourceCallQueryMechanism.java:228) ~[ModuleA-2.1.0.jar:na]
    at org.eclipse.persistence.internal.queries.DatasourceCallQueryMechanism.insertObject(DatasourceCallQueryMechanism.java:377) ~[ModuleA-2.1.0.jar:na]
    at org.eclipse.persistence.internal.queries.StatementQueryMechanism.insertObject(StatementQueryMechanism.java:165) ~[ModuleA-2.1.0.jar:na]
    at org.eclipse.persistence.internal.queries.StatementQueryMechanism.insertObject(StatementQueryMechanism.java:180) ~[ModuleA-2.1.0.jar:na]
    at org.eclipse.persistence.internal.queries.DatabaseQueryMechanism.insertObjectForWrite(DatabaseQueryMechanism.java:489) ~[ModuleA-2.1.0.jar:na]
    at org.eclipse.persistence.queries.InsertObjectQuery.executeCommit(InsertObjectQuery.java:80) ~[ModuleA-2.1.0.jar:na]
    at org.eclipse.persistence.queries.InsertObjectQuery.executeCommitWithChangeSet(InsertObjectQuery.java:90) ~[ModuleA-2.1.0.jar:na]
    at org.eclipse.persistence.internal.queries.DatabaseQueryMechanism.executeWriteWithChangeSet(DatabaseQueryMechanism.java:301) ~[ModuleA-2.1.0.jar:na]
    at org.eclipse.persistence.queries.WriteObjectQuery.executeDatabaseQuery(WriteObjectQuery.java:58) ~[ModuleA-2.1.0.jar:na]
    at org.eclipse.persistence.queries.DatabaseQuery.execute(DatabaseQuery.java:899) ~[ModuleA-2.1.0.jar:na]
    at org.eclipse.persistence.queries.DatabaseQuery.executeInUnitOfWork(DatabaseQuery.java:798) ~[ModuleA-2.1.0.jar:na]
    at org.eclipse.persistence.queries.ObjectLevelModifyQuery.executeInUnitOfWorkObjectLevelModifyQuery(ObjectLevelModifyQuery.java:108) ~[ModuleA-2.1.0.jar:na]
    at org.eclipse.persistence.queries.ObjectLevelModifyQuery.executeInUnitOfWork(ObjectLevelModifyQuery.java:85) ~[ModuleA-2.1.0.jar:na]
    at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.internalExecuteQuery(UnitOfWorkImpl.java:2896) ~[ModuleA-2.1.0.jar:na]
    at org.eclipse.persistence.internal.sessions.AbstractSession.executeQuery(AbstractSession.java:1802) ~[ModuleA-2.1.0.jar:na]
    at org.eclipse.persistence.internal.sessions.AbstractSession.executeQuery(AbstractSession.java:1784) ~[ModuleA-2.1.0.jar:na]
    at org.eclipse.persistence.internal.sessions.AbstractSession.executeQuery(AbstractSession.java:1735) ~[ModuleA-2.1.0.jar:na]
    at org.eclipse.persistence.internal.sessions.CommitManager.commitChangedObjectsForClassWithChangeSet(CommitManager.java:273) ~[ModuleA-2.1.0.jar:na]
    at org.eclipse.persistence.internal.sessions.CommitManager.commitAllObjectsForClassWithChangeSet(CommitManager.java:193) ~[ModuleA-2.1.0.jar:na]
    at org.eclipse.persistence.internal.sessions.CommitManager.commitAllObjectsWithChangeSet(CommitManager.java:139) ~[ModuleA-2.1.0.jar:na]
    at org.eclipse.persistence.internal.sessions.AbstractSession.writeAllObjectsWithChangeSet(AbstractSession.java:4205) ~[ModuleA-2.1.0.jar:na]
    at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.commitToDatabase(UnitOfWorkImpl.java:1441) ~[ModuleA-2.1.0.jar:na]
    at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.commitToDatabaseWithChangeSet(UnitOfWorkImpl.java:1531) ~[ModuleA-2.1.0.jar:na]
    at org.eclipse.persistence.internal.sessions.RepeatableWriteUnitOfWork.commitRootUnitOfWork(RepeatableWriteUnitOfWork.java:278) ~[ModuleA-2.1.0.jar:na]
    at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.commitAndResume(UnitOfWorkImpl.java:1169) ~[ModuleA-2.1.0.jar:na]
    at org.eclipse.persistence.internal.jpa.transaction.EntityTransactionImpl.commit(EntityTransactionImpl.java:134) ~[ModuleA-2.1.0.jar:na]
    ... 6 common frames omitted
Caused by: org.postgresql.util.PSQLException: ERROR: duplicate key value violates unique constraint "pkey_records_id"
  Détail : Key (id)=(280) already exists.
    at org.postgresql.core.v3.QueryExecutorImpl.receiveErrorResponse(QueryExecutorImpl.java:2198) ~[ModuleA-2.1.0.jar:na]
    at org.postgresql.core.v3.QueryExecutorImpl.processResults(QueryExecutorImpl.java:1927) ~[ModuleA-2.1.0.jar:na]
    at org.postgresql.core.v3.QueryExecutorImpl.execute(QueryExecutorImpl.java:255) ~[ModuleA-2.1.0.jar:na]
    at org.postgresql.jdbc2.AbstractJdbc2Statement.execute(AbstractJdbc2Statement.java:561) ~[ModuleA-2.1.0.jar:na]
    at org.postgresql.jdbc2.AbstractJdbc2Statement.executeWithFlags(AbstractJdbc2Statement.java:419) ~[ModuleA-2.1.0.jar:na]
    at org.postgresql.jdbc2.AbstractJdbc2Statement.executeUpdate(AbstractJdbc2Statement.java:365) ~[ModuleA-2.1.0.jar:na]
    at org.eclipse.persistence.internal.databaseaccess.DatabaseAccessor.executeDirectNoSelect(DatabaseAccessor.java:890) ~[ModuleA-2.1.0.jar:na]
    ... 38 common frames omitted

好的,我找到问题了

我甚至尝试更改表模式,删除自动生成的列,因此没有序列,但仍然是应用程序生成值的主键。但也有例外

这个问题很容易解决:为每个线程使用一个新的实体管理器

就在那里!不再有插入异常;)


谢谢大家。

这不应该发生:序列是安全的:问题可能在其他地方。这是怎么回事:
@Id@GeneratedValue(strategy=GenerationType.AUTO,generator=“records\u Id\u seq”)@SequenceGenerator(name=“records\u Id\u seq”,sequenceName=“MY\u ENTITY\u seq”)私有长Id为什么应用程序试图同时插入两个具有相同id的对象?它们是相同的对象,还是只有ID相同?你是怎么做到身份证是一样的?正如pdem所说,我认为您的程序逻辑中可能存在缺陷,这导致了问题(不一定是多线程)。在我看来,多个线程必须访问相同的对象,因此您尝试从多个线程插入相同的对象。在多线程中,我创建一个新的记录实体实例,构造函数不做任何事情,id为null,然后我合并实体(在此之前数据库中不存在该实体)。我对每个线程都使用相同的entityManager,这可能是问题吗?我正在为每个合并使用一个事务。