Hibernate Spring JPA 会话:具有相同标识符值的不同对象已与会话关联

Dan*_*ino 1 java spring hibernate jpa

我正在用 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]
Run Code Online (Sandbox Code Playgroud)

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

@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));
}
Run Code Online (Sandbox Code Playgroud)

我的股票类别:

@Id
private String stockId:

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

我的产品类别:

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

Nik*_*nko 5

您不应该以这种方式更新实体,这只适合创建新实体。

productRepo.save(prod)
Run Code Online (Sandbox Code Playgroud)

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

Product existing = productRepo.findById(prod.getId());
existing.getStock().setCount(+prod.getStock().getCount());
productRepo.save(existing);
Run Code Online (Sandbox Code Playgroud)

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