Java Hibernate ElementCollection/JoinTable IntegrityConstraintViolationException

Java Hibernate ElementCollection/JoinTable IntegrityConstraintViolationException,java,hibernate,spring-boot,spring-data-jpa,persistence,Java,Hibernate,Spring Boot,Spring Data Jpa,Persistence,我有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

我有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;
  ...
}
…或一次更新同一实体的多个ImageEntity

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引发等效错误):

检查数据库日志时,Hibernate似乎正在尝试:

  • 插入新映像(成功)
  • 更新现有映像(成功)
  • 将引用椅子和现有图像的条目插入联接表/集合表(椅子图像)。然后抛出这个JdbcSQLIntegrityConstraintViolationException,因为这个外键组合已经存在(旧映像以前已经存在)

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

    如果其他人遇到此问题,解决方法是:颠倒操作顺序:

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

    hibernate执行SQL语句的顺序保持不变,但由于之间的刷新,错误插入联接表的情况不再发生。

    @CollectionTable不应在此上下文中使用。它适用于字符串、枚举和可嵌入的基本类型,但不适用于实体:是的,你说得对。不过,hibernate在这个上下文中对待它的方式与@JoinTable相同。
    org.postgresql.util.PSQLException: ERROR: duplicate key value violates unique constraint "chair_image_pkey"
    
    chairEntity.getImages().add(new ImageEntity(...));
    chairRepository.saveAndFlush(chairEntity);
    chairEntity.getImages().stream().forEach(imageEntity -> {
      imageEntity.setDescription("some other description");
    }
    chairRepository.save(chairEntity); // crashes