Hibernate 映射關系

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。

@GeneratedValue

理解JPA注解@GeneratedValue

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,825評論 6 546
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,814評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事?!?“怎么了?”我有些...
    開封第一講書人閱讀 178,980評論 0 384
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 64,064評論 1 319
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,779評論 6 414
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 56,109評論 1 330
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 44,099評論 3 450
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,287評論 0 291
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,799評論 1 338
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,515評論 3 361
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,750評論 1 375
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,221評論 5 365
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,933評論 3 351
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,327評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,667評論 1 296
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,492評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,703評論 2 380

推薦閱讀更多精彩內容