You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

JPA双向一对一映射存值异常:从Course侧保存未写入course_id求助

双向一对一JPA映射外键未插入问题解决

问题本质

JPA双向关联中,只有维护方负责管理数据库中的外键字段。你的映射配置里:

  • CourseMaterial是关联的维护方:它通过@JoinColumn(name = "course_id")注解指定了外键字段,因此由它负责维护course_material表中course_id的值。
  • Course是关联的被维护方:@OneToOne(mappedBy = "course")注解表明,这个关联的控制权在CourseMaterial的course属性上,Course本身不负责更新外键。

当你通过CourseRepository保存数据时,只设置了Course.courseMaterial,但没有给维护方CourseMaterial设置对应的course属性,JPA因此不会更新course_material表的外键字段。

解决方案

方案1:手动维护双向关联的两端

修改CourseRepositoryTest中的saveCourse方法,在构建实体后,给CourseMaterial设置对应的Course实例:

@Test
public void saveCourse() {
    CourseMaterial courseMaterial = CourseMaterial.builder()
            .url("www.codejava.com")
            .build();

    Course course = Course.builder()
            .title("JAVA")
            .credit(6)
            .courseMaterial(courseMaterial)
            .build();

    // 关键:给维护方设置关联,触发外键更新
    courseMaterial.setCourse(course);

    courseRepository.save(course);
}

方案2:通过实体类自动维护双向关联(更优雅)

在Course类中重写setCourseMaterial方法,自动维护关联的另一端,避免每次手动设置:

@Entity
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
@ToString(exclude = "courseMaterial") // 取消注释避免循环引用
public class Course {
    // ... 原有字段定义

    @OneToOne(mappedBy = "course", cascade = CascadeType.ALL)
    private CourseMaterial courseMaterial;

    // 重写setter,自动维护双向关联
    @Override
    public void setCourseMaterial(CourseMaterial courseMaterial) {
        this.courseMaterial = courseMaterial;
        if (courseMaterial != null) {
            courseMaterial.setCourse(this);
        }
    }
}

同时记得给CourseMaterial类开启@ToString(exclude = "course"),避免打印实体时出现循环引用导致栈溢出。

修改后,直接运行saveCourse测试方法,course_material表的course_id就会被正确插入。

内容的提问来源于stack exchange,提问作者Satyam sahu

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.27 15:28:12