JPA实现多对多关系

本文已收录于专栏 《Java》


目录

概念说明

  多对多关系是指两个实体之间存在多对多的关联关系。在数据库中,多对多关系无法直接表示,需要通过中间表来实现。

  举个例子,假设有两个实体类:学生(Student)和课程(Course)。一个学生可以选择多门课程,而一门课程也可以被多个学生选择。这就是一个多对多的关系。

  在数据库中,可以创建三张表来表示多对多关系:学生表(students)、课程表(courses)和中间表(student_course)。中间表中存储了学生和课程之间的关联关系,它包含了学生的ID和课程的ID。

  通过中间表,可以将多对多关系拆分为两个一对多关系。学生和课程之间的关系可以被拆分为学生和中间表之间的一对多关系,以及课程和中间表之间的一对多关系。

优势利弊

  多对多关系的优点是能够灵活地表示实体之间的复杂关联关系。例如,在上述的学生和课程的例子中,一个学生可以选择多门课程,而一门课程也可以被多个学生选择。这种关系在实际应用中非常常见,通过多对多关系可以方便地表示和操作这种复杂的关联关系。

  多对多关系也有一些限制和注意事项。例如,中间表的设计和维护需要一定的注意,以确保关联关系的正确性和一致性。此外,多对多关系可能会导致性能问题,因为查询和操作涉及多个表的关联。因此,在设计和使用多对多关系时,需要仔细考虑和评估实际需求和性能要求。

实现方式

通过两个@ManyToMany注解实现

类图

代码

学生类

java 复制代码
@Entity
public class Student {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    
    private String name;
    
    @ManyToMany
    @JoinTable(name = "student_course",
               joinColumns = @JoinColumn(name = "student_id"),
               inverseJoinColumns = @JoinColumn(name = "course_id"))
    private List<Course> courses;
    
}

  在Student实体类中,使用@ManyToMany注解来表示多对多关系,并通过@JoinTable注解指定中间表的名称和关联字段。joinColumns指定了中间表中与Student实体关联的外键字段,inverseJoinColumns指定了中间表中与Course实体关联的外键字段。

课程类

java 复制代码
@Entity
public class Course {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    
    private String name;
    
    @ManyToMany(mappedBy = "courses")
    private List<Student> students;
    
}

  在Course实体类中,使用@ManyToMany(mappedBy = "courses")注解来表示多对多关系,并通过mappedBy属性指定了关联的属性名,即Student实体类中的courses属性。

中间表

  通过使用@ManyToMany的方式我们确实可以实现多对多的效果,但是我们没有办法在中间表中添加其他字段,中间表中只有学生的id和课程id。如果我们想要添加一些比如创建时间、更新时间、是否删除的字段是没有办法添加的。如果我们没有需要添加字段的需求那我们直接通过@ManyToMany 的方式即可。如果我们需要添加一些其他的字段就需要调整我们的实现方式。下面我们通过两个@OneToMany和两个@ManyToOne注解来解决这个问题。

通过@OneToMany和@ManyToOne注解实现

类图

代码

学生类

java 复制代码
@Entity
public class Student {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    
    private String name;
    
    @OneToMany(mappedBy = "student")
    private List<StudentCourse> studentCourses;
    
}

课程类

java 复制代码
@Entity
public class Course {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    
    private String name;
    
    @OneToMany(mappedBy = "course")
    private List<StudentCourse> studentCourses;
    
}

学生和课程关系类

java 复制代码
@Entity
@Table(name = "student_course")
public class StudentCourse {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    
    @ManyToOne
    @JoinColumn(name = "student_id")
    private Student student;
    
    @ManyToOne
    @JoinColumn(name = "course_id")
    private Course course;
    
    private int grade;
    
}

  这样,通过以上的配置,JPA会自动创建中间表,并维护学生和课程之间的关联关系,同时在中间表中添加了grade字段。你可以通过访问StudentCourse实体类来操作中间表的数据,包括添加学生选课、查询学生所选的课程以及对应的成绩等。

少走弯路

  当我们实现了多对多之后我们会发现在具体应用这些对象的时候会出现循环引用的问题,可能会导致堆栈溢出的问题。参考下面博客来解决循环引用带来的问题:

   https://blog.csdn.net/weixin_45490198/article/details/131795009

总结提升

  1. 在两个实体类中使用@ManyToMany注解来表示多对多关系,并通过@JoinTable注解指定中间表的名称和关联字段。
  2. JPA会自动创建中间表,并维护两个实体类之间的关联关系。
  3. 如果需要在中间表中添加其他字段,可以创建一个新的实体类来表示中间表,并在两个实体类中使用@OneToMany和@ManyToOne注解来表示与中间表的一对多关系。

🎯 此文章对你有用的话记得留言+点赞+收藏哦🎯

相关推荐
say_fall7 小时前
【Linux系统编程】Ext 文件系统:磁盘与存储、文件与目录、现代计算机究竟如何寻找文件
linux·运维·服务器·数据库·c++
码流子7 小时前
移动收费怎么做?手持终端+App+收费中心的架构实践
java·开发语言·架构
雪落漂泊7 小时前
C++算法 滑动窗口篇(下)
开发语言·c++
云创智城-yuncitys7 小时前
YunParking 4.0:JDK 17 与 Spring Boot 3.2 的停车云升级
java·开发语言·spring boot
郭小李7 小时前
openFeign入门
java·开发语言·前端
共享家95277 小时前
408 操作系统第一章
服务器·数据库·windows
wljt8 小时前
公司二-面试题
java·开发语言·mybatis
这个DBA有点耶8 小时前
连拿六年第一后宣布出海:国产数据库凭什么敢撕掉“平替”的标签?
数据库·人工智能·架构
Ramble_Naylor8 小时前
Rust深度解读:Send 与 Sync 的本质与线程安全边界
python·算法·rust
云和恩墨9 小时前
数据库监控简史:从会回答到能交付——AI-DBA如何成为真正的数字同事
数据库·人工智能·dba