这实际上是一个好问题,它有助于理解“拥有”实体的概念,因为双方都不需要@JoinTable 注释。如果您想防止双方都有join tables,这是个好主意,那么您需要在一侧有一个mappedBy= 元素。 @JoinTable 注解用于指定表名或映射关联的列。
先看Javadoc for @JoinTable:
指定关联的映射。它应用于关联的拥有方。
是否存在join table 由@ManyToMany 注释的mappedBy="name" 元素控制。 Javadoc for mappedBy for the ManyToMany annotation says:
拥有关系的字段。除非关系是单向的,否则是必需的。
对于 Hibernate (5.0.9.Final) 中的(双向)示例,如果只有两个 @ManyToMany 注释并且没有 mappedBy= 元素,则默认将有两个 Entity 表和两个 Join Tables:
Hibernate: create table Course (id bigint not null, primary key (id))
Hibernate: create table Course_Member (Course_id bigint not null, members_id bigint not null, primary key (Course_id, members_id))
Hibernate: create table Member (id bigint not null, primary key (id))
Hibernate: create table Member_Course (Member_id bigint not null, courses_id bigint not null, primary key (Member_id, courses_id))
虽然这是说每个实体“拥有”其ManyToMany 关系,但额外的join table 在典型用例中是多余的。但是,如果我决定让 Member 实体“拥有”该关系,那么我将 mappedBy= 元素添加到 Course 实体以指定它不拥有该关系:
@ManyToMany(mappedBy="courses")
Set<Member> members;
将@JoinTable(name="Member_Course") 添加到Member 实体不会改变任何东西:它只是将表命名为与它本来应该命名的相同。
由于Course 实体不再拥有其ManyToMany 关系,因此不会创建额外的JoinTable:
Hibernate: create table Course (id bigint not null, primary key (id))
Hibernate: create table Member (id bigint not null, primary key (id))
Hibernate: create table Member_Course (members_id bigint not null, courses_id bigint not null, primary key (members_id, courses_id))
这对开发人员很重要,因为他或她必须了解,除非将其添加到拥有实体(在本例中为 Member 实体),否则不会保留任何关系。但是,由于这是一种双向关系,开发人员应该将Course 添加到Member.courses 和Member 到Course.members。
因此,如果您有bidirectionalManyToMany 关系,这意味着您在所涉及的两个实体上都有ManyToMany,那么您应该在其中一个上添加mappedBy="name",以避免出现多余的join table。因为它是双向的,所以我认为你创建owning 实体的哪一方并不重要。与往常一样,启用 sql 日志并查看数据库中发生了什么总是一个好主意:
参考文献:
What is the difference between Unidirectional and Bidirectional associations?.
What does relationship owner means in bidirectional relationship?.
What is the “owning side” in an ORM mapping?.
Most efficient way to prevent an infinite recursion in toString()?.