我在Oracle DB中插入一些记录。为了唯一,我正在使用SequenceGenerator。下面是代码:

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与XxspPoInLine具有@ManyToOne关系。当我坚持XxspPoInLine实体时,我收到以下错误:

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)


我查看了stackoverflow,并找到了一些解决方案:
1.使用allocationSize = 1
由于我有5000+个XxspPoInLineLocqty,这将是我可以应用的最差的选择。我也尝试过此方法,但是40分钟后,我的网络开始波动,并且持续失败。我不能使用此选项,因为它会降低性能。

2.增加分配大小的值
我增加了allocationSize = 500,但是在不同的标识符(#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)


即使尝试了GenerationType.AUTO,也没有运气。
以下是Oracle DB上的序列:

CREATE SEQUENCE  "APPS"."LINE_LOCQTY_JPA_ID_SQ"  MINVALUE 1 MAXVALUE 999999999999999999999999999 INCREMENT BY 1 START WITH 7641 CACHE 20 NOORDER  NOCYCLE ;


我仍然很困惑为什么这个问题会出现。我不明白这个根本原因。有人可以向我解释此异常的根本原因,应该如何解决?

注意:在插入记录之前,我从表中删除了所有行。因此,当我执行上述顺序代码时,该表为空白。

最佳答案

allocationSize参数必须与序列的INCREMENT BY值匹配。

它的工作方式是Hibernate从序列(从数据库)中获取一个值,然后将该值保存在内存中并生成下一个X后续标识符(其中X = allocationSize)在内存中将该值加1,而无需到达数据库。

Hibernate生成X标识符后,它将从序列中获取下一个值,并生成新的X标识符,并将该值加1



一个简单的例子-假设:


@SequenceGenerator( ....allocationSize=5 ...)
CREATE SEQUENCE .... INCREMENT BY 1 ...


在上述情况下,Hibernate:


从序列中获取第一个数字-假设NextVal = 1并将其存储在内存中
生成下一个allocationSize=5标识符,将上面的值加1,即:Id = 1, 2, 3, 4, 5
从序列中获取下一个数字-由于INCREMENT BY 1nextVal将为:2
生成下一个allocationSize=5标识符,将上面的值加1,即:Id = 2, 3, 4, 5, 6


如您所见,它将导致双重错误。



现在请考虑这种情况:


@SequenceGenerator( ....allocationSize=5 ...)
CREATE SEQUENCE .... INCREMENT BY 5 ...


在这种情况下,休眠:


从序列中获取第一个数字-假设NextVal = 1并将其存储在内存中
生成下一个allocationSize=5标识符,将上面的值加1,即:Id = 1, 2, 3, 4, 5
从序列中获取下一个数字-由于INCREMENT BY 5nextVal将为:6
生成下一个allocationSize=5标识符,将上面的值加1,即:Id = 6, 7, 8, 9, 10


在这种情况下,没有重复错误。



最后一种情况的缺点是,如果该序列在Hibernate之外使用,则该序列将产生间隙。

10-04 17:56