如何解决无法添加或更新子行:Spring JPA 中的外键约束失败错误?
Posted
技术标签:
【中文标题】如何解决无法添加或更新子行:Spring JPA 中的外键约束失败错误?【英文标题】:How to solve Cannot add or update a child row: a foreign key constraint fails error in Spring JPA? 【发布时间】:2021-09-26 12:10:03 【问题描述】:我正在研究 Spring Boot api,其中我有一个实体模型课程,另一个是主题。
在一个课程下,我想要一个包含多个科目的列表。我正在使用 OneToMany
注释来执行此操作。
这是我的代码:
course.java
@Entity
@EntityListeners(AuditingEntityListener.class)
public class course
@Override
public String toString()
return "course [id=" + id + ", title=" + title + ", description=" + description + "]";
public long getId()
return id;
public void setId(int id)
this.id = id;
public String getTitle()
return title;
public void setTitle(String title)
this.title = title;
public String getDescription()
return description;
public void setDescription(String description)
this.description = description;
public List<subject> getSubjects()
return subjects;
public void setSubjects(List<subject> subjects)
this.subjects = subjects;
public String getProperty(String key)
switch (key)
case "title":
return this.title;
case "description":
return this.description;
case "date":
return this.date.toString();
case "id":
return Integer.toString(this.id);
default:
return "helo";
public course()
super();
// TODO Auto-generated constructor stub
public course(int id, String title, List<subject> subjects, String description, Date date)
super();
this.id = id;
this.title = title;
this.subjects = subjects;
this.description = description;
this.date = date;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
private String title;
@OneToMany
private List<subject> subjects;
private String description;
@CreatedDate
@Temporal(TemporalType.DATE)
private Date date;
public Date getDate()
return date;
public void setDate(Date date)
this.date = date;
subject.java
@Entity
public class subject
public String getName()
return name;
public void setName(String name)
this.name = name;
public String getComplexity()
return complexity;
public void setComplexity(String complexity)
this.complexity = complexity;
public subject(String name, String complexity)
super();
this.name = name;
this.complexity = complexity;
@Id
private String name;
private String complexity;
现在当我发送POST
请求时:
"title":"test course sossk",
"description":"Is it",
"subjects":[
"name":"java",
"complexity":"easy"
,
"name":"c++",
"complexity":"easy"
]
我收到这样的错误:
SQL Error: 1452, SQLState: 23000
2021-07-18 20:01:48.818 ERROR 10408 --- [nio-8080-exec-2] o.h.engine.jdbc.spi.SqlExceptionHelper : Cannot add or update a child row: a foreign key constraint fails (`courses`.`course_subjects`, CONSTRAINT `FKgy72njp8nmip43dy1cwk43ue6` FOREIGN KEY (`subjects_name`) REFERENCES `subject` (`name`))
2021-07-18 20:01:48.819 INFO 10408 --- [nio-8080-exec-2] o.h.e.j.b.internal.AbstractBatchImpl : HHH000010: On release of batch it still contained JDBC statements
2021-07-18 20:01:48.861 ERROR 10408 --- [nio-8080-exec-2] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.springframework.dao.DataIntegrityViolationException:
我该如何解决这个问题?如何添加外键?
任何帮助将不胜感激。
Update
course.java
@Entity
@EntityListeners(AuditingEntityListener.class)
public class course
@Override
public String toString()
return "course [id=" + id + ", title=" + title + ", description=" + description + "]";
public int getId()
return id;
public void setId(int id)
this.id = id;
public String getTitle()
return title;
public void setTitle(String title)
this.title = title;
public List<subject> getSubjects()
return subjects;
public void setSubjects(List<subject> subjects)
this.subjects = subjects;
public String getDescription()
return description;
public void setDescription(String description)
this.description = description;
public String getProperty(String key)
switch (key)
case "title":
return this.title;
case "description":
return this.description;
case "date":
return this.date.toString();
case "id":
return Integer.toString(this.id);
default:
return "helo";
public course()
super();
// TODO Auto-generated constructor stub
public course(int id, String title, List<subject> subjects, String description, Date date)
super();
this.id = id;
this.title = title;
this.subjects = subjects;
this.description = description;
this.date = date;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
private String title;
@OneToMany(targetEntity = subject.class,cascade = CascadeType.ALL)
private List<subject> subjects;
private String description;
@CreatedDate
@Temporal(TemporalType.DATE)
private Date date;
public Date getDate()
return date;
public void setDate(Date date)
this.date = date;
subject.java
@Entity
public class subject
public String getName()
return name;
public void setName(String name)
this.name = name;
public String getComplexity()
return complexity;
public void setComplexity(String complexity)
this.complexity = complexity;
public subject(String name, String complexity)
super();
this.name = name;
this.complexity = complexity;
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private int id;
private String name;
private String complexity;
【问题讨论】:
缺少拥有方的@ManyToOne
-注解(即subject
)。我建议阅读有关该主题的教程,例如this one over at Baeldung。 --- 两点说明:在构造函数中对super()
的显式调用是多余的,如果不存在对super(...)
或this(...)
的显式调用,它们会被隐式插入。 - Java 中的类应始终以大写字母开头(course
-> Course
、subject
-> Subject
)。
你能指导我使用上面的简单实现吗?
对不起,我们不是代码编写服务。我不会提供实现。如果我要提供一个实现,它将使您无法自己解决它。从长远来看,自己解决挑战应该会让你受益更多。
不用担心,谢谢我自己试试
【参考方案1】:
@OneToMany(mappedBy="name")
private List<subject> subjects;
@ManyToOne
@JoinColumn(name="course_id", nullable=false) // should reference mapped column
private String name;
您的解决方案将是这样的。 也请参考OneToMany & ManyToOne mapping JPA / Hibernate
【讨论】:
我完成了解决方案的第一部分,实施工作正常。我应该使用第二部分,即ManyToOne
部分有什么具体原因吗?
@OneToMany
注解用于定义 Subject 类中的属性,该属性将用于映射 mappedBy 变量。
我理解,但不使用 ManyToOne 我的 api 工作完美。ManyToone 部分用于什么?
能否更新您的新代码?
如果关系是双向的,则必须使用mappedBy
元素来指定作为关系所有者的实体的关系字段或属性。您的案例targetEntity
(作为关联目标的实体类)已定义,因此对我来说似乎是正确的。【参考方案2】:
请参阅下面和评论中的说明。我使用 lombok @Data
来缩短 getter、setter、构造函数、tostring 的代码。
// Course.java
@Entity
@Data
@EntityListeners(AuditingEntityListener.class)
public class Course
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
@OneToMany(
cascade = CascadeType.ALL,
fetch = FetchType.EAGER,
mappedBy = "course", // we map the connection field in Subject entity
orphanRemoval = true // will delete Subjects linked
)
private List<Subject> subjects;
private String title;
private String description;
@CreatedDate
@Temporal(TemporalType.DATE)
private Date date;
// Subject.java
@Entity
@Data
public class Subject
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private int id;
// Here we complete the connection/relationship to the course
@ManyToOne
@JoinColumn(
name = "course_id",
nullable = false,
referencedColumnName = "id", // this `id` is the Course.id
foreignKey = @ForeignKey(name = "course_subject_fk")
)
private Course course;
private String name;
private String complexity;
总结一下关系:一个课程可以有很多科目,但一个科目只能分配给一个课程。
编辑
我在这里所做的是使关系成为双向的。意思是说,当您获取课程时,它会使用fetch = FetchType.EAGER
自动获取主题。如果您不希望这种行为,可以将值更改为 FetchType.LAZY
。在获取主题时也会返回课程。如果你也不想这样,可以使用龙目岛的@ToString(exclude = "course")
【讨论】:
以上是关于如何解决无法添加或更新子行:Spring JPA 中的外键约束失败错误?的主要内容,如果未能解决你的问题,请参考以下文章
:完整性约束违规:1452 无法添加或更新子行:laravel 迁移中的外键约束失败