问题
I am inserting some records in Oracle DB. For the uniqueness, I am using SequenceGenerator. Below is the code:
public class XxspPoInLineLocqty implements Serializable {
@Id
@SequenceGenerator(name = "SequenceLocIdGenerator", sequenceName = "LINE_LOCQTY_JPA_ID_SQ")
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "SequenceLocIdGenerator")
@Column(name="LINE_LOCQTY_JPA_ID")
private Long lineLocqtyJPAId;
//other fields..
}
XxspPoInLineLocqty is having @ManyToOne relation with XxspPoInLine. When I am persisting XxspPoInLine entity, I am receiving below error:
javax.persistence.EntityExistsException: A different object with the same identifier value was already associated with the session : [com.bcone.oracle.ebs.model.XxspPoInLineLocqty#76]
at org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:116)
at org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:155)
at org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:162)
at org.hibernate.internal.SessionImpl.firePersist(SessionImpl.java:804)
at org.hibernate.internal.SessionImpl.persist(SessionImpl.java:764)
at org.hibernate.jpa.event.internal.core.JpaPersistEventListener$1.cascade(JpaPersistEventListener.java:80)
at org.hibernate.engine.internal.Cascade.cascadeToOne(Cascade.java:391)
I looked on the stackoverflow and found some solutions for this:
1. Use allocationSize=1
Since I am having 5000+ XxspPoInLineLocqty
, this would be the worst option I could apply. I tried this as well but after 40min my network got fluctuate and persisting got failed. I cannot use this option as it degrade the performance.
2. Increse the value of allocation size I increased the allocationSize=500, but still faced the same issue at different identifier(#372).
javax.persistence.EntityExistsException: A different object with the same identifier value was already associated with the session : [com.bcone.oracle.ebs.model.XxspPoInLineLocqty#-372]
at org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:116)
at org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:155)
at org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:162)
at org.hibernate.internal.SessionImpl.firePersist(SessionImpl.java:804)
at org.hibernate.internal.SessionImpl.persist(SessionImpl.java:764)
at org.hibernate.jpa.event.internal.core.JpaPersistEventListener$1.cascade(JpaPersistEventListener.java:80)
at org.hibernate.engine.internal.Cascade.cascadeToOne(Cascade.java:391)
at org.hibernate.engine.internal.Cascade.cascadeAssociation(Cascade.java:316)
Even tried GenerationType.AUTO, but no luck. Below is the sequence on Oracle DB:
CREATE SEQUENCE "APPS"."LINE_LOCQTY_JPA_ID_SQ" MINVALUE 1 MAXVALUE 999999999999999999999999999 INCREMENT BY 1 START WITH 7641 CACHE 20 NOORDER NOCYCLE ;
I am still confused why this issue is coming up. I didn't understand the root cause of this. Can someone explain me the root cause of this exception, and what should be the work around?
Note : Before inserting the records, I deleted all the rows from table. So the table is blank when I execute the above sequnce code.
回答1:
allocationSize
parameter must match the INCREMENT BY
value of the sequence.
It works in such a way that Hibernate gets a value from the sequence (from the database), and then keeps that value in the memory and generates next X subsequent identifiers (where X=allocationSize) incrementing this value by 1 in the memory, without reaching for the database.
Once Hibernate generates X identifiers, it gets the next value from the sequence, and generates new X identifiers, incrementing that value by 1
A simple example - let say that:
@SequenceGenerator( ....allocationSize=5 ...)
CREATE SEQUENCE .... INCREMENT BY 1 ...
In the above case Hibernate:
- Fetches the first number from the sequence - let say
NextVal = 1
and stores it in the memory - Generates next
allocationSize=5
identifiers incrementing the above value by 1, that is:Id = 1, 2, 3, 4, 5
- Fetches the next number from the sequence - because of
INCREMENT BY 1
, thenextVal
will be:2
- Generates next
allocationSize=5
identifiers incrementing the above value by 1, that is:Id = 2, 3, 4, 5, 6
As you can see, it will cause a dulicate error.
Now please consider this case:
@SequenceGenerator( ....allocationSize=5 ...)
CREATE SEQUENCE .... INCREMENT BY 5 ...
In this case Hibernate:
- Fetches the first number from the sequence - let say
NextVal = 1
and stores it in the memory - Generates next
allocationSize=5
identifiers incrementing the above value by 1, that is:Id = 1, 2, 3, 4, 5
- Fetches the next number from the sequence - because of
INCREMENT BY 5
, thenextVal
will be:6
- Generates next
allocationSize=5
identifiers incrementing the above value by 1, that is:Id = 6, 7, 8, 9, 10
In this case there is no duplicate error.
The last case has the disadvantage that if the sequence is used outside of Hibernate, then the sequence will produce gaps.
来源:https://stackoverflow.com/questions/48020829/javax-persistence-entityexistsexception-with-sequencegenerator