【问题标题】:Hibernate Spring JPA Session: A different object with the same identifier value was already associated with the sessionHibernate Spring JPA Session:具有相同标识符值的不同对象已与会话相关联
【发布时间】:2018-03-27 07:43:56
【问题描述】:

我正在用 Java 建立一个网上商店,我目前正在处理产品的库存。一切正常,但是我似乎遇到了这个令人困惑的错误,我不知道如何解决。

javax.persistence.EntityExistsException: A different object with the same identifier value was already associated with the session : [nl.scalda.platenbaas.model.Stock#0191400002005]
at org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:118) ~[hibernate-core-5.2.12.Final.jar:5.2.12.Final]
at org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:157) ~[hibernate-core-5.2.12.Final.jar:5.2.12.Final]
at org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:164) ~[hibernate-core-5.2.12.Final.jar:5.2.12.Final]
at org.hibernate.internal.SessionImpl.fireMerge(SessionImpl.java:916) ~[hibernate-core-5.2.12.Final.jar:5.2.12.Final]
at org.hibernate.internal.SessionImpl.merge(SessionImpl.java:875) ~[hibernate-core-5.2.12.Final.jar:5.2.12.Final]
at org.hibernate.engine.spi.CascadingActions$6.cascade(CascadingActions.java:261) ~[hibernate-core-5.2.12.Final.jar:5.2.12.Final]
at org.hibernate.engine.internal.Cascade.cascadeToOne(Cascade.java:467) ~[hibernate-core-5.2.12.Final.jar:5.2.12.Final]
at org.hibernate.engine.internal.Cascade.cascadeAssociation(Cascade.java:392) ~[hibernate-core-5.2.12.Final.jar:5.2.12.Final]
at org.hibernate.engine.internal.Cascade.cascadeProperty(Cascade.java:193) ~[hibernate-core-5.2.12.Final.jar:5.2.12.Final]
at org.hibernate.engine.internal.Cascade.cascade(Cascade.java:126) ~[hibernate-core-5.2.12.Final.jar:5.2.12.Final]
at org.hibernate.event.internal.DefaultMergeEventListener.cascadeOnMerge(DefaultMergeEventListener.java:461) ~[hibernate-core-5.2.12.Final.jar:5.2.12.Final]
at org.hibernate.event.internal.DefaultMergeEventListener.entityIsDetached(DefaultMergeEventListener.java:327) ~[hibernate-core-5.2.12.Final.jar:5.2.12.Final]
at org.hibernate.event.internal.DefaultMergeEventListener.onMerge(DefaultMergeEventListener.java:170) ~[hibernate-core-5.2.12.Final.jar:5.2.12.Final]
at org.hibernate.event.internal.DefaultMergeEventListener.onMerge(DefaultMergeEventListener.java:69) ~[hibernate-core-5.2.12.Final.jar:5.2.12.Final]
at org.hibernate.internal.SessionImpl.fireMerge(SessionImpl.java:883) ~[hibernate-core-5.2.12.Final.jar:5.2.12.Final]

我保存产品和更新库存的方法:

@PostMapping("/products")
public ResponseEntity<Product> save(@RequestBody Product prod) {
    if (!productRepo.existsById(prod.getEancode())) {
        return ResponseEntity.ok().body(productRepo.save(prod));
    }
    prod.getStock().setCount(+prod.getStock().getCount());

    return ResponseEntity.ok().body(productRepo.save(prod));
}

我的股票类:

@Id
private String stockId:

@JsonBackReference
@OneToOne(cascade = {PERSIST, MERGE}, fetch = FetchType.LAZY)
@JoinColumn(name = "eancode")
@MapsId
private Product product;

我的产品类别:

@JsonManagedReference
@OneToOne(cascade = {PERSIST, MERGE}, fetch = FetchType.LAZY, mappedBy = "product")
private Stock stock;

【问题讨论】:

    标签: java spring hibernate jpa


    【解决方案1】:

    您不应该以这种方式更新实体,这仅适用于创建新实体。

    productRepo.save(prod)
    

    正确的方法是首先通过 id 加载实体(这会将对象附加到会话),更新它然后保存

    Product existing = productRepo.findById(prod.getId());
    existing.getStock().setCount(+prod.getStock().getCount());
    productRepo.save(existing);
    

    但是在您的代码中,您会收到具有现有 ID (!) 的“非托管”(未附加到休眠会话)对象,更新并保存。当然会报错

    【讨论】:

    • 非常感谢!事实上,这似乎是一个非常简单且合乎逻辑的解决方案!
    【解决方案2】:

    仅针对那些在接受的答案中没有找到解决方案的人 - 我在引入 VERSION 列时遇到了相同的异常(通过 @Version 注释)。 我发布这个是因为在我们的案例中,异常具有误导性,其他人可能会遇到同样的情况。

    更详细地,我们引入了 VERSION 列以解决并发更新问题。 问题出现是因为我们已经有一些记录在使用新列更改表时自动变为空(这是预期的行为,这里没有错)。 我们注意到只有在尝试更新 VERSION 列为空的行时才会触发异常

    我们通过运行一个脚本解决了这个问题,该脚本将 VERSION 列设置为 0(零)用于具有 null 的行。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-01-09
      • 2020-10-12
      • 1970-01-01
      • 2011-03-16
      • 2014-11-17
      • 2018-03-26
      • 1970-01-01
      相关资源
      最近更新 更多