0. 關聯關系映射
關聯關系映射,是映射關系中比較復雜的一種映射關系,總的說來有一對一、一對多和多對多幾種關系。細分起來他們又有單向和雙向之分。下面我們逐一介紹一下。
整個項目的代碼,以及用到的類庫,我就不一一介紹了,可以參考我的github,在workspace下有許多項目,對應關系如下表所示:
項目名稱 | 描述 |
---|---|
HibernateOne2OneUNI | 單向一對一 |
HibernateOne2OneBI | 雙向一對一 |
HibernateOne2ManyUNI | 單向一對多 |
HibernateMany2OneUNI | 單向多對一 |
HibernateOne2ManyBI | 雙向一對多 |
HibernateMany2ManyUNI | 單向多對多 |
HibernateMany2ManyBI | 雙向多對多 |
具體的代碼和測試可以參考我的Github,鏈接為:GitHub地址
1. @OneToOne 單向關聯
Hasband 對Wife: OneToOne Husband單向擁有Wife。
- Hasband.java:
@Entity
public class Husband {
private int id;
private String name;
private Wife wife;
@Id
@GeneratedValue(strategy =GenerationType.IDENTITY)
public int getId() {
return id;
}
public String getName() {
return name;
}
@OneToOne
public Wife getWife() {
return wife;
}
public void setWife(Wife wife) {
this.wife = wife;
}
public void setName(String name) {
this.name = name;
}
public void setId(int id) {
this.id = id;
}
}
- Wife.java:
@Entity
public class Wife {
private int id;
private String name;
@Id
@GeneratedValue(strategy =GenerationType.IDENTITY)
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
2. @OneToOne 雙向關聯
雙向關系有一方為關系的擁有端,另一方是關系的反端,也就是“Inverse”端。在這里例子中 Husband擁有這個關系,而 Wife就是關系的“Inverse”端。Wife中我們定義了一個 husband屬性,在這個屬性上我們使用了 @OneToOne 注解并且定義了他的“mappedBy”屬性,這個在雙向關系的“Inverse”端是必需的,在下面將要介紹的雙向關系中也要用到這個屬性。Hasband.java與單向關系一樣, Wife.java如下。
- Wife.java
@Entity
public class Wife {
private int id;
private String name;
private Husband huaband;
@OneToOne(mappedBy = "wife")
public Husband getHuaband() {
return huaband;
}
public void setHuaband(Husband huaband) {
this.huaband = huaband;
}
@Id
@GeneratedValue(strategy =GenerationType.IDENTITY)
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
3. @ManyToOne 單向關聯
只需在單這一方寫@ManyToOne注解,這里我們用學生和課程舉例,學生是One這一方,課程是Many一方。
- Course.java
@Entity
public class Course {
private int id;
private String name;
private Student student;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@ManyToOne
public Student getStudent() {
return student;
}
public void setStudent(Student student) {
this.student = student;
}
}
- Student.java
@Entity
public class Student {
private int id;
private String name;
...
4. @OneToMany 單向關聯
只寫@OneToMany,Hibernate會認為存在一張中間表,要加@Joincolumn。@Joincolumn的name是studentId,不要寫成courseId,因為他出現在course這張表里,表示的是course表中student的ID
這里我們用學生和課程舉例,學生是One這一方,課程是Many一方。
- Student.java
@Entity
public class Student {
private int id;
private String name;
private List<Course> courses = new ArrayList<Course>();
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@OneToMany(cascade = CascadeType.ALL)
@JoinColumn(name = "studentid")
public List<Course> getCourses() {
return courses;
}
public void setCourses(List<Course> courses) {
this.courses = courses;
}
}
- Course.java
@Entity
public class Course {
private int id;
private String name;
@Id
@GeneratedValue(strategy =GenerationType.IDENTITY)
...
5. @ManyToOne 雙向關聯
還是一樣,這里我們用學生和課程舉例,學生是One這一方,課程是Many一方。雙向非常簡單,只需要在單的一方加上mappedBy即可。
- Student.java
@Entity
public class Student {
private int id;
private String name;
private List<Course> courses = new ArrayList<Course>();
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@OneToMany(mappedBy="student")
public List<Course> getCourses() {
return courses;
}
public void setCourses(List<Course> courses) {
this.courses = courses;
}
}
Course.java
@Entity
public class Course {
private int id;
private String name;
private Student student;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@ManyToOne
public Student getStudent() {
return student;
}
public void setStudent(Student sutdent) {
this.student = sutdent;
}
}
6. @ManyToMany 單向關聯
使用@ManyToMany, 表示的意思是一個學生可以選多門課程。
@JoinTable(name = "s_c", joinColumns = { @JoinColumn(name = "student_id") }, inverseJoinColumns = { @JoinColumn(name = "course_id") }為中間表的表名和列名
- Student.java
@Entity
public class Student {
private int id;
private String name;
private List<Course> courses = new ArrayList<Course>();
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@ManyToMany
@JoinTable(name = "s_c", joinColumns = { @JoinColumn(name = "student_id") }, inverseJoinColumns = {
@JoinColumn(name = "course_id") })
public List<Course> getCourses() {
return courses;
}
public void setCourses(List<Course> courses) {
this.courses = courses;
}
}
- Course.java
@Entity
public class Course {
private int id;
private String name;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
7. @ManyToMany 雙向關聯使用
@ManyToMany, 表示的意思是一個學生可以選多門課程。一門課程可以有多個學生選擇,關系被維護方需要加mappedBy。@JoinTable的解釋看第6節。
- Student.java
@Entity
public class Student {
private int id;
private String name;
private List<Course> courses = new ArrayList<Course>();
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@ManyToMany
@JoinTable(name = "s_c", joinColumns = { @JoinColumn(name = "student_id") }, inverseJoinColumns = {
@JoinColumn(name = "course_id") })
public List<Course> getCourses() {
return courses;
}
public void setCourses(List<Course> courses) {
this.courses = courses;
}
}
- Course.java
@Entity
public class Course {
private int id;
private String name;
private List<Student> students = new ArrayList<Student>();
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@ManyToMany(mappedBy = "courses")
public List<Student> getStudents() {
return students;
}
public void setStudents(List<Student> students) {
this.students = students;
}
}
7. 關鍵字
MappedBy
mappedBy的意思就是“被映射”,即mappedBy這方不用管關聯關系,關聯關系交給另一方處理
規律:
凡是雙向關聯,mapped必設,因為根本都沒必要在2個表中都存在一個外鍵關聯,在數據庫中只要定義一邊就可以了
- 只有OneToOne,OneToMany,ManyToMany上才有mappedBy屬性,ManyToOne不存在該屬性;
- mappedBy標簽一定是定義在the owned side(被擁有方的),他指向the owning side(擁有方);
- mappedBy的含義,應該理解為,擁有方能夠自動維護 跟被擁有方的關系;
當然,如果從被擁有方,通過手工強行來維護擁有方的關系也是可以做到的。 - mappedBy跟JoinColumn/JoinTable總是處于互斥的一方,可以理解為正是由于擁有方的關聯被擁有方的字段存在,擁有方才擁有了被 擁有方。mappedBy這方定義的JoinColumn/JoinTable總是失效的,不會建立對應的字段或者表
Cascade
hibernate一對多關系中,會用到級聯操作.即:有collection的一端操作,被關聯的表被自動操作.
這時有collection一端需要配置<set cascade="?">,即用在一對多的一方。
Cascade 屬性值:
- none:在保存、刪除修改對象的時候,不考慮其附屬物的操作。
- save-update:在保存、更新當前對象時,級聯保存、更新附屬物。
- delete:在刪除當前對象時,級聯刪除附屬物。
- all: 包含save-update和delete的操作,但不包括delete-orphan的操作。
- delete-orphan:刪除和當前對象解除關系的附屬對象。
- all-delete-orphan:所用情況。
fetch
fetch = FetchType.EAGER: 那么表示取出這條數據時,它關聯的數據也同時取出放入內存中,因為在內存里,所以在session外也可以取。
fetch = FetchType.LAZY:取出這條數據時,它關聯的數據并不取出來,在同一個session中,什么時候要用,就什么時候取(再次訪問數據庫)。 但是,在session外,就不能再取了。用EAGER時。
一般只在一邊設Eager,JPA接口默認為一對多為Lazy,多對一為Eager,但是Hibernate反向工程生成Entity時,多對一為Lazy,需要手動改為Eager。
而兩邊都設Eager,那么代碼中取一條記錄時,會發2次SQL。