java - Hibernate两次向Join Table插入数据导致Spring Boot项目出现 "ORA-00001: unique constraint violated"

标签 java oracle hibernate rest spring-boot

我有两个使用 @ManyToMany 注释映射的实体

第一

皮耶格尼亚卡:


 @Data
 @Entity
 @Table(name = "pielegniarka")
 public class Pielegniarka {

    @Id
    @SequenceGenerator(name = "seq2", sequenceName = "pielegniarka_id_pielegniarki", allocationSize = 1)
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "seq2")
    @Column(name = "id_pielegniarki", nullable = false, unique = true)
    private int id_pielegniarki;

    @Column(name = "imie")
    private String imie;

    @Column(name = "nazwisko")
    private String nazwisko;

    @Column(name = "placa")
    private int placa;


    @ManyToMany(fetch = FetchType.LAZY, cascade = {CascadeType.DETACH,CascadeType.MERGE,
            CascadeType.PERSIST,CascadeType.REFRESH})
    @JoinTable(
            name = "pielegniarki_sale",
            joinColumns = @JoinColumn(name = "id_pielegniarki"),
            inverseJoinColumns = @JoinColumn(name = "nr_sali")
    )
    private List<Sala> sale;


    public Pielegniarka() {
    }

    public Pielegniarka(String imie, String nazwisko, int placa, List<Sala> sale) {
        this.imie = imie;
        this.nazwisko = nazwisko;
        this.placa = placa;
        this.sale = sale;
    }

    public void addSala(Sala sala){
        if(sale == null){
            sale = new ArrayList<>();
        }
        sale.add(sala);
    }

    public void removeSala(Sala sala){
        sale.remove(sala);
        sala.getPielegniarki().remove(this);
    }
}

第二

萨拉:

@Data
@Entity
@Table
public class Sala {

    @Id
    @SequenceGenerator(name = "seq3", sequenceName = "sala_nr_sali_seq", allocationSize = 1)
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "seq3")
    @Column(name = "nr_sali", nullable = false, unique = true)
    private int nr_sali;

    @Column(name = "pojemnosc")
    private int pojemnosc;

    @Column(name = "oddzial")
    private String oddzial;

    @JsonBackReference
    @ManyToMany(fetch = FetchType.LAZY, cascade = {CascadeType.DETACH,CascadeType.MERGE,
            CascadeType.PERSIST,CascadeType.REFRESH})
    @JoinTable(
            name = "pielegniarki_sale",
            joinColumns = @JoinColumn(name = "nr_sali"),
            inverseJoinColumns = @JoinColumn(name = "id_pielegniarki")
    )
    private List<Pielegniarka> pielegniarki;


    public Sala() {
    }

    public Sala(int pojemnosc, String oddzial, List<Pielegniarka> pielegniarki) {
        this.pojemnosc = pojemnosc;
        this.oddzial = oddzial;
        this.pielegniarki = pielegniarki;
    }

    public void addPielegniarka(Pielegniarka pielegniarka){
        if(pielegniarki == null){
            pielegniarki = new ArrayList<>();
        }
        pielegniarki.add(pielegniarka);
    }

    public void removePielegniarka(Pielegniarka pielegniarka){
        pielegniarki.remove(pielegniarka);
        pielegniarka.getSale().remove(this);
    }
}

我的 SalaDAO 中还有一个方法(以及 PielegniarkaDAO 中的类似方法),它将 Pielegniarka 添加到 Sala 类中的列表,然后将该 Sala 的 id 和新添加的 Pielegniarko 的 id 插入到我的 Oracle 数据库中的联接表中(因为 @ ManyToMany注释)

  @Override
    public void saveSalaWithIdPielegniarki(int idPielegniarki, int nr_sali) {
        Pielegniarka pielegniarka = entityManager.find(Pielegniarka.class, idPielegniarki);
        Sala sala = entityManager.find(Sala.class, nr_sali);

        if (pielegniarka != null && sala != null) {
            for (Pielegniarka salPiel : sala.getPielegniarki()) {
                if (salPiel.getId_pielegniarki() == idPielegniarki) {
                    return;
                }
            }
            pielegniarka.addSala(sala);
            sala.addPielegniarka(pielegniarka);
        }

    }

这是 SalaController 的一个片段,显示了执行此操作的方法。在服务类中我使用了与 DAO 中完全相同的方法。它只是 DAO 类的包装器。

@RestController
@RequestMapping("/sala")
public class SalaController {

 @PostMapping("/{nr_sali}/pielegniarka/{idPielegniarki}")
    public void saveSalaWithIdPielegniarki(@PathVariable int idPielegniarki,
                                           @PathVariable int nr_sali) {
        salaService.saveSalaWithIdPielegniarki(idPielegniarki,nr_sali);
    }

}

当我尝试访问此端点时,例如/sala/4/pielegniarka/5 ,它应该将 id 为 5 的 Pielegniarka 添加到 id 为 4 的 sala 列表中,Hibernate 会将 id 为 4,5 的记录插入到ielegniarki_sale JOIN TABLE中两次我的数据库。什么可能导致此错误?

Oracle 因此抛出“ORA-00001:违反唯一约束”。

这是显示双插入的 Spring Boot 日志的图片。与实体关系图片

Unique constraint violated error

MER

最佳答案

您使用同一个关系表两次定义了 ManyToMany 关系。

您必须将其中一个关系设为拥有关系,将一个关系设为相反关系。

拥有方是关系中维护中间关系表的一方(插入、更新、删除),另一方,即所谓的反向方,是在插入、更新方面没有发生任何事情的一方并删除。

当您使用指向拥有方属性的mappedBy属性时,定义了受控方。

例如,您可以拥有这样的所有权方:

@ManyToMany(fetch = FetchType.LAZY, cascade = {CascadeType.DETACH,CascadeType.MERGE,
        CascadeType.PERSIST,CascadeType.REFRESH})
@JoinTable(
        name = "pielegniarki_sale",
        joinColumns = @JoinColumn(name = "nr_sali"),
        inverseJoinColumns = @JoinColumn(name = "id_pielegniarki")
)
private List<Pielegniarka> pielegniarki;

然后反面是这样的:

@ManyToMany(fetch = FetchType.LAZY, cascade = {CascadeType.DETACH,CascadeType.MERGE,
        CascadeType.PERSIST,CascadeType.REFRESH}, mappedBy = "pielegniarki")
private List<Pielegniarka> pielegniarki;

如果您不这样做并让它像您的映射一样,那么 Hibernate 会尝试将同一记录插入到关系表中两次。

关于java - Hibernate两次向Join Table插入数据导致Spring Boot项目出现 "ORA-00001: unique constraint violated",我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59546543/

相关文章:

java - 领域驱动设计中工厂和接口(interface)的使用

Java 原语拓宽面试

c# - DateTime 精度差异.NET 与 Java

java - Java 中 ORACLE 函数 MONTHS_BETWEEN 的模拟

oracle - 尝试使用 ODP .NET 进行连接时出现 ORA-12154 错误

java - 如何创建一个包含原始主键和复合主键作为表复合键的 JoinTable(Spring JPA)?

java - 如何获取多对多关系实体

java - 参数值 [2018-04-08T11 :02:44] did not match expected type [java. util.Date (n/a)]

java - Java 中通用列表的过滤和排序项目

android - 你能告诉我如何从 Oracle 数据库中检索图像到我的 android Activity 吗