JPA实现多对多关系

本文介绍了Java中使用JPA处理多对多关系的方法,包括通过@ManyToMany注解直接实现和通过@OneToMany和@ManyToOne注解结合中间实体类的方式来实现。讨论了多对多关系的优势和潜在问题,并提供了示例代码展示如何在实体类中定义关联。同时,文章提醒了在实际应用中要注意的循环引用问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

本文已收录于专栏
《Java》

概念说明

  多对多关系是指两个实体之间存在多对多的关联关系。在数据库中,多对多关系无法直接表示,需要通过中间表来实现。
  举个例子,假设有两个实体类:学生(Student)和课程(Course)。一个学生可以选择多门课程,而一门课程也可以被多个学生选择。这就是一个多对多的关系。
  在数据库中,可以创建三张表来表示多对多关系:学生表(students)、课程表(courses)和中间表(student_course)。中间表中存储了学生和课程之间的关联关系,它包含了学生的ID和课程的ID。
  通过中间表,可以将多对多关系拆分为两个一对多关系。学生和课程之间的关系可以被拆分为学生和中间表之间的一对多关系,以及课程和中间表之间的一对多关系。

优势利弊

  多对多关系的优点是能够灵活地表示实体之间的复杂关联关系。例如,在上述的学生和课程的例子中,一个学生可以选择多门课程,而一门课程也可以被多个学生选择。这种关系在实际应用中非常常见,通过多对多关系可以方便地表示和操作这种复杂的关联关系。
  多对多关系也有一些限制和注意事项。例如,中间表的设计和维护需要一定的注意,以确保关联关系的正确性和一致性。此外,多对多关系可能会导致性能问题,因为查询和操作涉及多个表的关联。因此,在设计和使用多对多关系时,需要仔细考虑和评估实际需求和性能要求。

实现方式

通过两个@ManyToMany注解实现

类图

在这里插入图片描述

代码

学生类

@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实体关联的外键字段。

课程类

@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注解实现

类图

在这里插入图片描述

代码

学生类

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

课程类

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

学生和课程关系类

@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注解来表示与中间表的一对多关系。

🎯 此文章对你有用的话记得留言+点赞+收藏哦🎯
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

武梓龙_Wzill

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值