Hibernate 两次将数据插入到 Join Table 中,导致 Spring Boot 项目中出现“ORA-00001:违反唯一约束”
Posted
技术标签:
【中文标题】Hibernate 两次将数据插入到 Join Table 中,导致 Spring Boot 项目中出现“ORA-00001:违反唯一约束”【英文标题】:Hibernate inserts data into Join Table twice causing "ORA-00001: unique constraint violated" in Spring Boot project 【发布时间】:2020-04-20 03:02:57 【问题描述】:我有两个用@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 数据库中的 Join Table 中(因为 @多对多注释)
@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 的记录两次插入到 pielegniarki_sale JOIN TABLE 中我的数据库。什么会导致此错误?
Oracle 正因此抛出“ORA-00001:违反唯一约束”。
这是显示双重插入的 Spring Boot 日志图片。与实体关系图片
Unique constraint violated error
MER
【问题讨论】:
您可以为这些表格上传一张 MER 的图片吗? 添加图片@BugsForBreakfast 嗯,从简单的角度来看,一切看起来都很好,但是由于您正在使用 SEQUENCE,所以您是否确保在您的数据库中没有重复的 id 或序列不是“因水的原因而中断?例如,id 为 28,而您的序列当前为 27,因此它尝试使用 28 并导致错误发生,请检查是否丢弃:p 【参考方案1】:您已经两次定义了与同一个房地产表的多对多关系。
您必须将其中一种关系设为拥有,而将一种关系设为反方。
拥有方是关系中维护中间关系表的一方(插入、更新、删除),而另一方,即所谓的反向方,是在插入、更新方面没有发生任何事情的一方并删除。
当您使用指向拥有方属性的 mappedBy 属性时,定义了 inserves 方。
例如,您可以拥有这样的拥有方:
@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 会尝试将两次相同的记录插入到关系表中。
【讨论】:
非常感谢,您的回答对我有帮助!但准确地说。当我在做 pielegniarka.add(sala) 和 sala.add(pielegniarka) 时,他们都在向 JOIN TABLE 添加记录? 是的。请查看文档docs.jboss.org/hibernate/orm/5.4/userguide/html_single/…以上是关于Hibernate 两次将数据插入到 Join Table 中,导致 Spring Boot 项目中出现“ORA-00001:违反唯一约束”的主要内容,如果未能解决你的问题,请参考以下文章
spring2.5+hibernate3.2+struts2.0插入数据时调用两次sql语句
是否可以使用 Cakephp 中的 saveAll 一次将所有相关记录插入到 HABTM 中?
在 Python 中:一次将 QtableWidget 中的所有条目插入数据库表中