@ManyToMany 注解

@ManyToMany 注解用来定义具有多对多多重性的多值关联。

每个多对多关系都有两个方面,关系的拥有方和非拥有方。连接表(中间表)在关系的拥有方指定。

如果关联是双向的,任何一方都可以被指定为关系的拥有方。

如果关系是双向的,则关系的非拥有方必须使用 @ManyToMany 注解的 mappingBy 属性来指定拥有方的关系字段或属性。例如:

public class Teacher {
    //...
    @ManyToMany(mappedBy = "teacherList")
    private List<Student> studentList;
}

public class Student {
    //...
    @ManyToMany
    private List<Teacher> teacherList;
}

上面代码中,在 Teacher 中使用 mappedBy 指定多对多关系由 Student 中的 teacherList 进行维护。Student 则为关系的拥有方,关联表也由 Student 维护。

@ManyToMany 注解可以在包含在实体类中的可嵌入类中使用,以指定与实体集合的关系。

如果关系是双向的,并且包含可嵌入类的实体是关系的所有者,则非拥有方必须使用 @ManyToMany 注解的 mappingBy 属性来指定可嵌入类的关系字段或属性。

在 mappedBy 元素中必须使用点(“.”)符号语法来指示嵌入属性中的关系属性。与点符号一起使用的每个标识符的值是相应嵌入字段或属性的名称。

@ManyToMany 注解属性详解:

  • targetEntity:(可选)指定关联目标的实体类。只有当使用 Java 泛型定义集合值关系属性时才可选,默认为集合的参数化类型。否则,必须另外指定 targetEntity 属性。例如:

@ManyToMany
private List<Student> students;

@ManyToMany(targetEntity=Student.class)
private List students;
  • cascade:(可选)指定级联到关联目标的操作。当目标集合是 java.util.Map 时,级联元素适用于映射值(即 Map 中的 value)。默认值为 {} 

  • fetch:(可选)关联是应该延迟加载还是必须马上加载。EAGER 策略表示必须马上获取关联的实体,LAZY 策略表示用到关联对象时才去加载。默认值为 javax.persistence.FetchType.LAZY 

  • mappedBy:拥有关系的字段,单向关系不需要指定改属性;双向关系必须指定改属性的值。默认值为空字符串,例如:教师和学生的关系,一个学生有多个老师,一个老师有多个学生。代码如下:

public class Teacher {
    //...
    @ManyToMany(mappedBy = "teacherList")
    private List<Student> studentList;
}

public class Student {
    //...
    @ManyToMany
    private List<Teacher> teacherList;
}

上面代码中,在 Teacher 中使用 mappedBy 指定多对多关系由 Student 中的 teacherList 进行维护。执行它,会创建如下三张表:

CREATE TABLE `student` (
  `id` int(11) NOT NULL,
  `name` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

CREATE TABLE `student_teacher` (
  `STUDENTLIST_ID` int(11) DEFAULT NULL,
  `TEACHERLIST_ID` int(11) DEFAULT NULL,
  KEY `I_STDNCHR_ELEMENT` (`TEACHERLIST_ID`),
  KEY `I_STDNCHR_STUDENTLIST_ID` (`STUDENTLIST_ID`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

CREATE TABLE `teacher` (
  `id` int(11) NOT NULL,
  `name` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

其中,student_teacher 表将由 Student 进行维护(新增、修改和删除);而 Teacher 是关系的被维护方。如果我们去掉 Teacher  中的 mappedBy 属性,JPA 将会创建四张表,分别如下:

CREATE TABLE `student` (
  `id` int(11) NOT NULL,
  `name` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

CREATE TABLE `student_teacher` (
  `STUDENTLIST_ID` int(11) DEFAULT NULL,
  `TEACHERLIST_ID` int(11) DEFAULT NULL,
  KEY `I_STDNCHR_ELEMENT` (`TEACHERLIST_ID`),
  KEY `I_STDNCHR_STUDENTLIST_ID` (`STUDENTLIST_ID`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

CREATE TABLE `teacher` (
  `id` int(11) NOT NULL,
  `name` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

CREATE TABLE `teacher_student` (
  `TEACHER_ID` int(11) DEFAULT NULL,
  `STUDENTLIST_ID` int(11) DEFAULT NULL,
  KEY `I_TCHRDNT_ELEMENT` (`STUDENTLIST_ID`),
  KEY `I_TCHRDNT_TEACHER_ID` (`TEACHER_ID`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

此时,多对多的关系同时被 Teacher 和 Student 进行维护,显然维护两份关系是多余的,浪费资源。我们可以使用 mappedBy 属性放弃一方去放弃关系维护 @ManyToMany(mappedBy = "teacherList") 要求 Teacher 方放弃关系维护。

说说我的看法
全部评论(
没有评论
关于
本网站专注于 Java、数据库(MySQL、Oracle)、Linux、软件架构及大数据等多领域技术知识分享。涵盖丰富的原创与精选技术文章,助力技术传播与交流。无论是技术新手渴望入门,还是资深开发者寻求进阶,这里都能为您提供深度见解与实用经验,让复杂编码变得轻松易懂,携手共赴技术提升新高度。如有侵权,请来信告知:hxstrive@outlook.com
公众号