使用SequenceGenerator的javax.persistence.EntityExistsException

时间:2017-12-29 10:06:27

标签: java oracle hibernate jpa-2.0

我在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 ;

我仍然感到困惑,为什么会出现这个问题。我不明白这个的根本原因。有人可以向我解释这个例外的根本原因,应该解决什么问题?

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

1 个答案:

答案 0 :(得分:2)

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

它的工作原理是Hibernate从序列中获取一个值(来自数据库),然后将该值保存在内存中并生成下一个X后续标识符(其中X = allocationSize)将此值递增1记忆,没有到达数据库。

一旦Hibernate生成X标识符,它就会从序列中获取下一个值,并生成新的X标识符,将该值递增1

一个简单的例子 - 让我们说:

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

在上面的例子中Hibernate:

  1. 从序列中获取第一个数字 - 让我们说NextVal = 1并将其存储在内存中
  2. 生成下一个allocationSize=5标识符,将上述值递增1,即:Id = 1, 2, 3, 4, 5
  3. 从序列中获取下一个数字 - 由于INCREMENT BY 1nextVal将为:2
  4. 生成下一个allocationSize=5标识符,将上述值递增1,即:Id = 2, 3, 4, 5, 6
  5. 正如您所看到的,它会导致错误的错误。

    现在请考虑这个案例:

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

    在这种情况下,Hibernate:

    1. 从序列中获取第一个数字 - 让我们说NextVal = 1并将其存储在内存中
    2. 生成下一个allocationSize=5标识符,将上述值递增1,即:Id = 1, 2, 3, 4, 5
    3. 从序列中获取下一个数字 - 由于INCREMENT BY 5nextVal将为:6
    4. 生成下一个allocationSize=5标识符,将上述值递增1,即:Id = 6, 7, 8, 9, 10
    5. 在这种情况下,没有重复错误。

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