Search code examples
javaoracle-databasejpaeclipselink

EclipseLink generates duplicate primary keys on an Oracle DB


I am using EclipseLink 2.4.2 (in combination with Spring, but I don't think it has anything to do with our issue here) and we had a few times the following exception:

org.springframework.transaction.TransactionSystemException: Could not commit JPA transaction; nested exception is javax.persistence.RollbackException: Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.4.2.v20130514-5956486): org.eclipse.persistence.exceptions.DatabaseException

Internal Exception: java.sql.SQLIntegrityConstraintViolationException: ORA-00001 : unique constraint (****.PK_*****) violated

Our primary keys are generated by EclipseLink which uses an Oracle sequence to allocate them. I double checked, and the allocationSize matches exactly the increment by defined on the sequence.

Here is an example of how this sequence is defined in our Java class:

@Id
@SequenceGenerator(name = "SOME_GENERATOR", sequenceName = "SOME_SEQ", allocationSize = 10000, initialValue = 1)
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "SOME_GENERATOR")
@Column(name = "ID")
private Long id;

Here is the sequence creation SQL-statement:

CREATE SEQUENCE SOME_SEQ INCREMENT BY 10000 START WITH 10000;

Of course, the problem is hardly reproduceable and only happens randomly. It seems to happen more often when the server is under heavy load.

I don't know if this is relevant, but here are some extra infos:

  • We have two servers accessing the same database
  • The primary key definition is inherited by many classes

My first thinking would be that this is related to concurrency, but it would seem like a rather severe issue for such a mature framework. Any other thing I should verify or that I could have overlooked?

I have looked at related posts such as theses ones:

but they don't seem to help in my case.


Solution

  • We eventually found an explanation to this issue.

    The actual problem came from the fact that the database was reset (so drop tables and sequences, then re-initialize everything), but the application server wasn't.

    • So in the beginning, EclipseLink was still allocating id's from the previous pre-allocated queue (e.g, [100016,100017,100018,100019,100020]].
    • Then when it hit the end of it, it restarted from the initial value ([1,2,3,4,5,...]).
    • After a while, EclipseLink reached ids that had already been allocated and hence we were hitting this Primary Key constraint violation.

    Since the ids are used by multiple entities, the behaviour was rather random and collisions were actually not likely to occur.

    Developers and testers will now always restart application server after a reset of the DB.