@OneToOne
單向關系
假設學生和學生卡是一對一關系,那么:
學生類:
import lombok.Data;
import javax.persistence.*;
import java.io.Serializable;
@Entity
@Data
@Table(name = "student")
public class Student implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false)
private String name;
@OneToOne(cascade = CascadeType.ALL)
@JoinColumn(name = "card_id")
private Card card;
}
學生卡類:
import lombok.Data;
import javax.persistence.*;
import java.io.Serializable;
@Entity
@Table(name = "card")
@Data
public class Card implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false)
private Integer number;
}
生成的數據庫表如下:


- @OneToOne和@JoinColumn定義了關系維護端
- 關系維護端(Student)生成的數據庫表包含外鍵,關系被維護端(Card)生成的數據庫表不包含外鍵
- 當保存關系維護端(Student)前,會先保存關系被維護端(Card),同時更新外鍵值;
- 如果設置了級聯刪除,當刪除關系維護端(Student)時,關系被維護端(Card)將一塊被刪除;否則只刪除關系維護端(Student)自己
- 單向關系只保證關系維護端(Student)的每個實例有且只有一個Card實例,但無法保證一個關系被維護端(Card)的實例只被一個關系維護端(Student)的實例引用即一張學生卡可能對應多個人
- 當刪除關系被維護端(Card)時,程序報錯
Cannot delete or update a parent row: a foreign key constraint fails,是由於被維護端的數據被通過外鍵引用無法刪除
雙向
如果更改為雙向關系,只需改動關系被維護端:
import lombok.Data;
import javax.persistence.*;
import java.io.Serializable;
@Entity
@Table(name = "card")
@Data
public class Card implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false)
private Integer number;
@OneToOne(mappedBy = "card")
private Student student;
}
- @OneToOne的
mappedBy屬性定義了關系被維護端,表示主動讓出放棄維護權,由當前被標注字段所屬類型(Student類)的類屬性名(card屬性名)負責維護關系,類屬性名是當前類的實例或實例集合 - 關系維護端(Student)生成的數據庫表包含外鍵,關系被維護端(Card)生成的數據庫表不包含外鍵
- 當保存關系維護端(Student)前,會先保存關系被維護端(Card),同時更新外鍵值;如果通過關系被維護端來保存關系維護端實例,關系維護端實例會保存,但外鍵值為空或不更新
- 雙向關系保證關系維護端(Student)的每個實例有且只有一個Card實例,同時保證關系被維護端(Card)的實例只被一個關系維護端(Student)的實例引用
@OneToMany
單向
假設一個學校有多個教師,那么:
學校類:
import lombok.Data;
import javax.persistence.*;
import java.io.Serializable;
import java.util.List;
@Entity
@Table(name = "school")
@Data
public class School implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false)
private String name;
@OneToMany(cascade = CascadeType.ALL)
@JoinColumn(name = "schoolIDid")
private List<Teacher> teacherList;
}
教師類:
import lombok.Data;
import javax.persistence.*;
import java.io.Serializable;
import java.util.List;
@Entity
@Table(name = "teacher")
@Data
public class Teacher implements Serializable{
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false)
private String name;
@ManyToOne
@JoinColumn(name = "schoolIDid")
private School school;
}
生成的數據庫表如下:


在一對多關系中,多的一方是關系維護端即@ManyToOne定義關系維護端,@OneToMany定義關系被維護端
關系維護端生成的數據庫表包含外鍵,關系被維護端生成的數據表不包含外鍵。
關系維護端負責外鍵記錄的更新,關系被維護端沒有權利更新外鍵字段
@JoinColumn作用:
- 阻止生成中間表。如果想阻止生成中間表,關系被維護端(一的一方)必須標注@JoinColumn
- 指定外鍵名。默認外鍵名為關系被維護端的表名加下划線加id,如果指定外鍵名則關系維護端和關系被維護端都必須標注@JoinColumn
如果關系被維護端沒有使用@JoinColumn,那么數據庫會生成中間表:

不同於一對一關系,關系維護端保存前必須先維護關系被維護端,否則報錯
雙向
只須在關系被維護端的@OneToMany注解中添加mappedBy屬性
@MonyToMony
單向
一對多和一對一關系,可以用外鍵實現;多對多關系只能通過中間表進行映射。
假設一個學生有多個老師,一個老師有多個學生,那么:
關系維護端注解如下:
@ManyToMany (cascade = CascadeType.REFRESH)
@JoinTable (//關聯表
name = "student_teacher" , //關聯表名
inverseJoinColumns = @JoinColumn (name = "teacher_id" ),//被維護端外鍵
joinColumns = @JoinColumn (name = "student_id" ) //維護端外鍵
)
private Set<Teacher> teachers;
關系被維護端注解如下:
@ManyToMany (fetch = FetchType.LAZY)
@JoinTable (//關聯表
name = "student_teacher" , //關聯表名
inverseJoinColumns = @JoinColumn (name = "student_id" ),//被維護端外鍵
joinColumns = @JoinColumn (name = "teacher_id" ) //維護端外鍵
)
private Set<Student> students;
- 關系維護端刪除時,如果中間表存在些紀錄的關聯信息,則會刪除該關聯信息
- 關系被維護端刪除時,如果中間表存在些紀錄的關聯信息,則會刪除失敗
關聯表名 = 主表表名+_下划線+從表表名
joinColumns屬性=當前實體類數據庫表名+_下划線+id
雙向
關系維護端注解不變,關系被維護端注解更改為:
@ManyToMany (fetch = FetchType.LAZY,
mappedBy = "teachers", //通過維護端的屬性關聯
cascade = CascadeType.REFRESH
)
private Set<Student> students;
