【问题标题】:Hibernate ElementCollection/JoinTable IntegrityConstraintViolationExceptionHibernate ElementCollection/JoinTable IntegrityConstraintViolationException
【发布时间】:2020-01-08 19:06:41
【问题描述】:

我有 3 个这样的 JPA 实体以及相应的 JPA 存储库。

@Entity
public class ChairEntity {
  ...
  @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
  @JoinTable(name = "chair_image")
  private Set<ImageEntity> images = new HashSet<>();
  ...
}

@Entity
public class TableEntity {
  ...
  @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
  @JoinTable(name = "table_image")
  private Set<ImageEntity> images = new HashSet<>();
  ...
}


@Entity
public class ImageEntity{
  ...
  private String description;
  @Lob
  private byte[] data;
  ...
}

使用 REST-API 创建和更新这些对象。这通常可以正常工作,例如我可以像这样一次添加多个图像实体(所有代码块都在它们自己的事务中)

chairEntity.getImages().add(new ImageEntity(..));
chairEntity.getImages().add(new ImageEntity(..));
chairRepository.save(chairEntity);

...或者一次更新同一个 chairEntity 的多个 ImageEntities。

chairEntity.getImages().stream().forEach(imageEntity -> {
  imageEntity.setDescription("some other description");
}
chairRepository.save(chairEntity);

在这两种情况下,所有更改都已成功级联并保存。

但是,如果我要更新现有的 ImageEntity 以及添加另一个实体,则会失败:

chairEntity.getImages().stream().forEach(imageEntity -> {
  imageEntity.setDescription("some other description");
}
chairEntity.getImages().add(new ImageEntity(...));
chairRepository.save(chairEntity); // crashes

异常如下(使用h2db抛出等效错误):

org.postgresql.util.PSQLException: ERROR: duplicate key value violates unique constraint "chair_image_pkey"

在检查 DB-Log 时,Hibernate 似乎正在尝试:

  1. 插入新图像(成功)
  2. 更新现有图像(成功)
  3. 将条目插入到连接表/集合表 (chair_image) 中,引用椅子和现有图像。然后抛出这个 JdbcSQLIntegrityConstraintViolationException,因为这个外键组合已经存在(旧图像之前已经存在)。

为什么会发生这种情况,我该如何解决?在同一事务中单独保存和刷新更改似乎也不起作用。

【问题讨论】:

  • @CollectionTable 不应在此上下文中使用。它适用于字符串、枚举和可嵌入等基本类型,但不适用于实体:docs.oracle.com/javaee/7/api/javax/persistence/…
  • 是的,你是对的。尽管如此,在这种情况下,hibernate 还是以与 @JoinTable 相同的方式对待它。

标签: java hibernate spring-boot spring-data-jpa persistence


【解决方案1】:

一种解决方法,以防其他人遇到此问题:颠倒操作顺序:

chairEntity.getImages().add(new ImageEntity(...));
chairRepository.saveAndFlush(chairEntity);
chairEntity.getImages().stream().forEach(imageEntity -> {
  imageEntity.setDescription("some other description");
}
chairRepository.save(chairEntity); // crashes

hibernate 执行 SQL-Statements 的顺序保持不变,但由于之间的刷新,错误插入 Join-Table 的情况不再发生。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-11-10
    • 2010-12-19
    • 2012-07-13
    • 1970-01-01
    • 2018-01-12
    • 2014-08-22
    • 2012-06-03
    • 1970-01-01
    相关资源
    最近更新 更多