SSH:Hibernate框架(七種關聯關係映射及配置詳解)

概念

 

       基本映射是對一個實體進行映射,關聯映射就是處理多個實體之間的關係,將關聯關係映射到數據庫中,所謂的關聯關係在對象模型中有一個或多個引用。

 

分類


         

            

        關聯關係分爲上述七種,但是由於相互之間有各種關係,可以簡化,例如:多對一與一對多映射,只是側重的角度不對而已。

 

映射技巧

 

       映射技巧是小編寫映射文件的過程,總結的經典內容,總共分爲四步,咋看不是特別易懂,但是效果很好。下面我們以實例看技巧。


(1)寫註釋

         格式爲:?屬性,表達的是本對象與?的?關係。

         解釋:在寫映射文件之前先寫註釋,將問號的地方填上相應的內容。例如:<!-- group屬性,表達的是本對象(User)與Group的多對一的關係-->

 

(2)寫映射的框架(拷模版)

 

多對一

<many-to-one name=“” class=“” column=“”/>

一對多

Set

<set name="">

        <key column=""></key>

        <one-to-many class=""/>

</set>

多對多

Set

<set name="" table="">

        <key column=""></key>

        <many-to-many class="" column=""/>

</set>

 

 

(3)填空

          填空,就是將映射的框架信息,填寫完成,完成映射文件。

          • name屬性:屬性名(註釋中的第1問號)
          • class屬性:關聯的實體類型(註釋中的第2個問號)
          • column屬性:
               ○ <many-to-one column="..">:一般可以寫成屬性名加Id後綴,如屬性爲group,則column值寫成groupId。
               ○ 一對多中的<key column="..">:從關聯的對方(對方是多對一)映射中把column值拷貝過來。 
               ○ 多對多中的<key column=“..”>:一般可以寫成本對象的名加Id後綴,如本對象名爲User,則寫爲userId。
               ○ 多對多中的<many-to-many column=“..”>:一般可以寫爲關聯對象的名稱加Id後綴。
 

(4)完成

          將映射文件添加到hibernate.hbm.xml中,這個相信大家都知道爲什麼。

      

          我們後面所有關聯映射的博文都使用此映射技巧來寫映射文件,明白之後,速度會非常快。



(一)多對一關聯映射
 

映射原理

 

       多的一端維護關聯關係,在“多”的一端加入一個外鍵,指向“一”的一端。多的一端持有一的一端的引用,即在“多”的一端加外鍵,指向“一”的一端。

 

實例

 

       比如,多個用戶屬於同一組,我們從對象模型和關係模型兩個角度來分析一下這個例子,如下:

      從上圖可以看出,對象模型具有方向性,通過用戶(User)可以看到組(Group),但是不能反過來。用戶和組各對應一張數據庫表,聚合關係需要一個外鍵(groupid)來表示,最後生成的表如下所示:

 

作用:

      當我拿到用戶時直接就可以拿到用戶的組,hibernate在訪問多的一端時,可以自動的加載關聯對象。對於用戶(User)來說,它的關聯對象是組(group)。

 

      上面都是多對一關聯映射的基本原理,以及相應的實例,下面我們看一下代碼:

 

 代碼

User類

  1. public class User {  
  2.     private int id;  
  3.     private String name;  
  4.     private Group group;  
  5.           
  6.     public int getId() {  
  7.         return id;  
  8.     }  
  9.     public void setId(int id) {  
  10.         this.id = id;  
  11.     }  
  12.     public String getName() {  
  13.         return name;  
  14.     }  
  15.     public void setName(String name) {  
  16.         this.name = name;  
  17.     }  
  18.     public Group getGroup() {  
  19.         return group;  
  20.     }  
  21.     public void setGroup(Group group) {  
  22.         this.group = group;  
  23.     }  
  24. }  

Group類

  1. public class Group {  
  2.     private int id;  
  3.     private String name;  
  4.     public int getId() {  
  5.         return id;  
  6.     }  
  7.     public void setId(int id) {  
  8.         this.id = id;  
  9.     }  
  10.     public String getName() {  
  11.         return name;  
  12.     }  
  13.     public void setName(String name) {  
  14.         this.name = name;  
  15.     }  

User.hbm.xml

  1. <?xml version="1.0"?>  
  2. <!DOCTYPE hibernate-mapping PUBLIC   
  3.     "-//Hibernate/Hibernate Mapping DTD 3.0//EN"  
  4.     "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">  
  5. <hibernate-mapping package="com.liang.hibernate">  
  6.     <class name="User" table="t_user">  
  7.         <id name="id">  
  8.             <generator class="native"></generator>  
  9.         </id>  
  10.         <property name="name"></property>  
  11.         <!-- group屬性,表達的是本對象與Group的多對一的關係-->  
  12.         <many-to-one name="group" class="Group" column="groupid"></many-to-one>  
  13.         <!-- 解釋:  
  14.             多對一關係標籤:  
  15.             <many-to-one name=“” class=“” column=“”/>  
  16.               
  17.             1、第1個問號:group是User類的屬性,對應於name屬性名  
  18.             2、第2個問號:class表達的是本對象(User)與Group的關係  
  19.             3、第3個問號:column是屬性名+Id  
  20.             當我們寫完註釋之後,我們直接拷貝問號的對應關係即可。  
  21.          -->  
  22.     </class>  
  23. </hibernate-mapping>  

 Group.hbm.xml

  1. <?xml version="1.0"?>  
  2. <!DOCTYPE hibernate-mapping PUBLIC   
  3.     "-//Hibernate/Hibernate Mapping DTD 3.0//EN"  
  4.     "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">  
  5. <hibernate-mapping>  
  6.     <class name="com.liang.hibernate.Group" table="t_group">  
  7.         <id name="id">  
  8.             <generator class="native"></generator>  
  9.         </id>  
  10.         <property name="name"></property>  
  11.     </class>  
  12. </hibernate-mapping>  

 

生成的表結構,與上面的分析的關係模型一樣:
          

 

      項目中,多對一關聯映射是最常見的映射,但它是Hibernate的關聯映射中最簡單的一種映射關係。




(二)一對一單向關聯映射

 

映射原理

 

      兩個實體對象之間是一對一的關聯映射,即一個對象只能與另外唯一的一個對象相對應。例如:一個人(Person)只有一張身份證(IdCard)。我們看一下這個例子的對象模型,如下圖所示:

 

對象模型

 

       

        從上圖中可以看出:

        1、一個人只有一張身份證,唯一的一個身份證號,對象之間是一對一的關係;

        2、人(Person)持有身份證(IdCard)的引用,所以,兩個對象關係維護由person端決定。

        從對象模型映射成關係模型,有兩種方式:主鍵關聯和唯一外鍵關聯,我們繼續看下面的內容。

 

分類: 

 

 主鍵關聯:

 

        1、兩個實體對象的主鍵一樣,以表明它們之間的一一對應關係;

        2、不需要多餘的外鍵字段來維護關係,僅通過主鍵來關聯,即Person的主鍵要依賴IdCard的主鍵,他們共用一個主鍵值。

        以上兩點恰與唯一外鍵關聯相反。

 

 主鍵關聯的關係模型

 Person.hbm.xml

  1. <?xml version="1.0"?>  
  2. <!DOCTYPE hibernate-mapping PUBLIC   
  3.     "-//Hibernate/Hibernate Mapping DTD 3.0//EN"  
  4.     "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">  
  5. <hibernate-mapping package="com.liang.hibernate">  
  6.     <class name="Person" table="t_person">  
  7.         <id name="id">  
  8.         <!-- 採用foreign生成策略,forgeign會取得另外一個關聯對象的標識 -->  
  9.             <generator class="foreign" >  
  10.                 <param name="property">idCard</param>  
  11.             </generator>  
  12.         </id>  
  13.         <property name="name"></property>  
  14.         <!--   
  15.             one-to-one指示hibernate如何加載其關聯對象,默認根據主鍵加載  
  16.             也就是拿到關係字段值,根據對端的主鍵來加載關聯對象  
  17.               
  18.             constrained="true"表示約束,當前主鍵(person的主鍵)還是一個外鍵  
  19.             參照了對端的主鍵(IdCard的主鍵),也就是會生成外鍵約束語句  
  20.          -->  
  21.          <!-- idCard屬性,表達的是本對象與IdCard的一對一關係。 -->  
  22.         <one-to-one name="idCard" class="IdCard"  constrained="true"></one-to-one>  
  23.     </class>  
  24. </hibernate-mapping>  

生成的表結構以及測試數據:

 

唯一外鍵關聯:

 

       1、兩個實體對象用一個外鍵來關聯,以表表明對象之間的關係。

       2、其實它是多對一關聯映射的特例,多的一端加上唯一的限制之後,用來表示一對一的關聯關係

       所以它採用多對一的標籤來映射,如下所示:

  1. <!-- 採用<mang-to-one>標籤來映射,指定多的一端unique爲true,  
  2.     這樣就限制了多的一端的多重性爲一,就是這樣來映射的。  
  3. -->  
  4. <many-to-one name="" unique="true"></many-to-one>  

唯一外鍵的關係模型

Person.hbm.xml

  1. <?xml version="1.0"?>  
  2. <!DOCTYPE hibernate-mapping PUBLIC   
  3.     "-//Hibernate/Hibernate Mapping DTD 3.0//EN"  
  4.     "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">  
  5. <hibernate-mapping package="com.liang.hibernate">  
  6.     <class name="Person" table="t_person">  
  7.         <id name="id">  
  8.             <generator class="native" ></generator>  
  9.         </id>  
  10.         <property name="name"></property>  
  11.         <!-- 由於它是一對一的唯一外鍵關聯,它是多對一關聯的特例,註釋可以直接寫成多對一關聯-->  
  12.         <!-- idCard屬性,表達的是本對象與IdCard的多對一關係。 -->  
  13.         <many-to-one name="idCard" class="IdCard" column="idCardId" unique="true"></many-to-one>      
  14.     </class>  
  15. </hibernate-mapping>  

生成的表結構以及測試數據:

 

 

其他相同代碼如下:

Person

  1. public class Person {  
  2.     private int id;  
  3.     private String name;  
  4.     private IdCard idCard;  
  5.       
  6.     public IdCard getIdCard() {  
  7.         return idCard;  
  8.     }  
  9.     public void setIdCard(IdCard idCard) {  
  10.         this.idCard = idCard;  
  11.     }  
  12.     public int getId() {  
  13.         return id;  
  14.     }  
  15.     public void setId(int id) {  
  16.         this.id = id;  
  17.     }  
  18.     public String getName() {  
  19.         return name;  
  20.     }  
  21.     public void setName(String name) {  
  22.         this.name = name;  
  23.     }  
  24. }  

IdCard

  1. public class IdCard {  
  2.     private int id;  
  3.     private String cardNo;  
  4.     public int getId() {  
  5.         return id;  
  6.     }  
  7.     public void setId(int id) {  
  8.         this.id = id;  
  9.     }  
  10.     public String getCardNo() {  
  11.         return cardNo;  
  12.     }  
  13.     public void setCardNo(String cardNo) {  
  14.         this.cardNo = cardNo;  
  15.     }  
  16. }  

IdCard.hbm.xml

  1. <?xml version="1.0"?>  
  2. <!DOCTYPE hibernate-mapping PUBLIC   
  3.     "-//Hibernate/Hibernate Mapping DTD 3.0//EN"  
  4.     "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">  
  5. <hibernate-mapping package="com.liang.hibernate">  
  6.     <class name="IdCard" table="t_idCard">  
  7.         <id name="id">  
  8.             <generator class="native"></generator>  
  9.         </id>  
  10.         <property name="cardNo"></property>  
  11.     </class>  
  12. </hibernate-mapping>  

建議

 

由於一對一主鍵關聯映射具有以下兩個缺點:

      1、靈活性差,沒有辦法改成多對一關聯映射,不能應變多變的需求;

      2、必須先保存關聯對象IdCard,之後才能保持Person;

所以,在映射一對一單向關聯映射時,我們採用唯一外鍵關聯映射。


(三)一對一雙向關聯映射


上面我們介紹了一對一的單向關聯映射,單向是指只能從人(Person)這端加載身份證端(IdCard),但是反過來,不能從身份證端加載人得信息。如圖所示:

      

      關鍵原因在於對象模型具有方向性:

單向:一端只能加載另一端,不能反過來。

雙向:兩端都可以加載另一端。

      問題來了:如何我們想從身份證端(IdCard)加載人(Person),怎麼辦呢?

      下面我們開始介紹一對一的雙向關聯映射。

 

 映射原理

 

       雙向關聯映射與單向關聯映射的原理是一樣的,雙向關聯映射並不影響存儲,隻影響加載。所以,雙向關聯映射和單向關聯映射的關係模型是一樣的即數據庫的表結構是一樣的,只是IdCard的實體類和配置文件(IdCard.hbm.xml)發生了一點點變化。

 

 對象模型

 

           

 

 從上圖中可以看出:

        1、一個人只有一張身份證,唯一的一個身份證號,對象之間是一對一的關係;

        2、兩個對象得關係維護還是由person端決定(因爲關係只能由一端維護主鍵,否則關係就亂了)。

 

       根據上面的對象模型,我們可以看到Person端沒有變化,但是要在IdCard端加上Person的引用,例如Person和IdCard實體類如下。

Person

  1. package com.liang.hibernate;  
  2.   
  3. public class Person {  
  4.     private int id;  
  5.     private String name;  
  6.     private IdCard idCard;  
  7.       
  8.     public IdCard getIdCard() {  
  9.         return idCard;  
  10.     }  
  11.     public void setIdCard(IdCard idCard) {  
  12.         this.idCard = idCard;  
  13.     }  
  14.     public int getId() {  
  15.         return id;  
  16.     }  
  17.     public void setId(int id) {  
  18.         this.id = id;  
  19.     }  
  20.     public String getName() {  
  21.         return name;  
  22.     }  
  23.     public void setName(String name) {  
  24.         this.name = name;  
  25.     }  
  26. }  

 IdCard

  1. package com.liang.hibernate;  
  2.   
  3. public class IdCard {  
  4.     private int id;  
  5.     private String cardNo;  
  6.     private Person person;  
  7.       
  8.     public Person getPerson() {  
  9.         return person;  
  10.     }  
  11.     public void setPerson(Person person) {  
  12.         this.person = person;  
  13.     }  
  14.     public int getId() {  
  15.         return id;  
  16.     }  
  17.   
  18.     public void setId(int id) {  
  19.         this.id = id;  
  20.     }  
  21.     public String getCardNo() {  
  22.         return cardNo;  
  23.     }  
  24.     public void setCardNo(String cardNo) {  
  25.         this.cardNo = cardNo;  
  26.     }  
  27. }  

 

     無論是單向關聯映射還是雙向關聯映射,他們都屬於一對一關聯映射,只是他們主鍵的生成策略不同,分爲主鍵關聯映射和唯一外鍵關聯映射。

     由於它們都屬於一對一關聯映射,所以,Hibernate封裝雙向關聯映射時,主鍵關鍵映射和唯一外鍵關聯映射的加載策略一樣,都採用的是一對一<one-to-one name=""></one-to-one>,只是屬性設置不一致,所以,下面我們分開來看IdCard的配置文件。

 

分類:

 

主鍵關聯映射

 

     同一對一單向關聯映射類似,主鍵關聯即利用主鍵進行關聯,關聯主鍵的值相同。下面我們看一下映射文件:

 

IdCard.hbm.xml

  1. <?xml version="1.0"?>  
  2. <!DOCTYPE hibernate-mapping PUBLIC   
  3.     "-//Hibernate/Hibernate Mapping DTD 3.0//EN"  
  4.     "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">  
  5. <hibernate-mapping package="com.liang.hibernate">  
  6.     <class name="IdCard" table="t_idCard">  
  7.         <id name="id">  
  8.             <generator class="native"></generator>  
  9.         </id>  
  10.         <property name="cardNo"></property>  
  11.         <!-- 怎麼加載對象,抓取策略:join聯合查詢(默認),select:一條條的查詢 -->  
  12.         <one-to-one name="person" class="Person" fetch="join"></one-to-one>  
  13.     </class>  
  14. </hibernate-mapping>  

Person.hbm.xml,同一對一單向主鍵關聯映射一樣

  1. <?xml version="1.0"?>  
  2. <!DOCTYPE hibernate-mapping PUBLIC   
  3.     "-//Hibernate/Hibernate Mapping DTD 3.0//EN"  
  4.     "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">  
  5. <hibernate-mapping package="com.liang.hibernate">  
  6.     <class name="Person" table="t_person">  
  7.         <id name="id">  
  8.         <!-- 採用foreign生成策略,forgeign會取得關聯對象的標識 -->  
  9.             <generator class="foreign" >  
  10.                 <param name="property">idCard</param>  
  11.             </generator>  
  12.         </id>  
  13.         <property name="name"></property>  
  14.         <!--   
  15.             one-to-one指示hibernate如何加載其關聯對象,默認根據主鍵加載  
  16.             也就是拿到關係字段值,根據對端的主鍵來加載關聯對象  
  17.               
  18.             constrained="true"表示,當前主鍵(person的主鍵)還是一個外鍵  
  19.             參照了對端的主鍵(IdCard的主鍵),也就是會生成外鍵約束語句  
  20.          -->  
  21.         <one-to-one name="idCard" class="IdCard" constrained="true"></one-to-one>  
  22.     </class>  
  23. </hibernate-mapping>  

生成的表結構

 

 

唯一外鍵關聯映射

    

       一對一雙向關聯映射的外鍵關聯映射也與一對一單向關聯映射的外鍵關聯映射類似,在其一對一的指向端(Person)存在一個唯一外鍵,該唯一外鍵與被指向端(IdCard)相關聯,關聯主鍵的值相同。下面我們看一下映射文件:
 

IdCard.hbm.xml

  1. <?xml version="1.0"?>  
  2. <!DOCTYPE hibernate-mapping PUBLIC   
  3.     "-//Hibernate/Hibernate Mapping DTD 3.0//EN"  
  4.     "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">  
  5. <hibernate-mapping package="com.liang.hibernate">  
  6.     <class name="IdCard" table="t_idCard">  
  7.         <id name="id">  
  8.             <generator class="native"></generator>  
  9.         </id>  
  10.         <property name="cardNo"></property>  
  11.         <!-- 一對一唯一外鍵關聯雙向採用<one-to-one>標籤來映射,必須指定<one-to-one>  
  12.             標籤中的property-ref屬性爲關係字段的名稱  
  13.          -->  
  14.         <one-to-one name="person" class="Person" property-ref="idCard"></one-to-one>  
  15.     </class>  
  16. </hibernate-mapping>  

Person.hbm.xml,同一對一單向唯一外鍵關聯映射一樣

  1. <?xml version="1.0"?>  
  2. <!DOCTYPE hibernate-mapping PUBLIC   
  3.     "-//Hibernate/Hibernate Mapping DTD 3.0//EN"  
  4.     "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">  
  5. <hibernate-mapping package="com.liang.hibernate">  
  6.     <class name="Person" table="t_person">  
  7.         <id name="id">  
  8.             <generator class="native" ></generator>  
  9.         </id>  
  10.         <property name="name"></property>  
  11.         <!-- 由於它是一對一的唯一外鍵關聯,它是多對一關聯的特例,註釋可以直接寫成多對一關聯-->  
  12.         <!-- idCard屬性,表達的是本對象與IdCard的多對一關係。 -->  
  13.         <many-to-one name="idCard" class="IdCard" column="idCardId" unique="true"></many-to-one>      
  14.     </class>  
  15. </hibernate-mapping>  

生成的表結構

        

 

對比

 

       一對一單向和雙向關聯映射的區別正是對象模型和關係模型的區別之一。

對象模型:有方向性。它到底是單向還是雙向是由對象模型決定的即配置文件決定。

關係模型:沒有方向性或者說是雙向的。從任何一端都可以加載另一端。

 

下載

 

         以上內容,只證明了一對一雙向關聯映射不影響存儲即沒有改變表結構,但不能證明關聯是雙向的,需要寫相應的測試用例,我們以源碼的形式給大家。源碼下載

 

 總結

 

       一對一雙向關聯映射並不是必須的,是由需求下決定的。如果沒有這樣的需求,用戶也沒有要求,系統也不需要,就沒有必要建立雙向的關聯映射。

 

(四)一對多關聯映射


映射原理

 

      一對多關聯映射和多對一關聯映射的映射原理是一致的,都是在多的一端加入一個外鍵,指向一的一端。關聯關係都是由多端維護,只是在寫映射時發生了變化。

 

多對一和一對多的區別

 

         多對一和一對多的區別在於維護的關係不同

(1)多對一:多端維護一端的關係,在加載多端時,可以將一端加載上來。

(2)一對多:一端維護多端的關係,在加載一端時,可以將多端加載上來。

 

分類

 

一對多單向關聯映射

 

對象模型

          

      從對象模型中,我們可以看出,Group持有User的一個引用。由於是單向關聯,所以數據在加載Group時,會把User加載上來,但是User並不知道Group的存在。

 

      我們先看一下Group和User的實體,以及映射文件。

Group

  1. package com.liang.hibernate;  
  2. import java.util.Set;  
  3. public class Group {  
  4.     private int id;  
  5.     private String name;  
  6.     private Set users;  
  7.       
  8.     public int getId() {  
  9.         return id;  
  10.     }  
  11.     public void setId(int id) {  
  12.         this.id = id;  
  13.     }  
  14.     public String getName() {  
  15.         return name;  
  16.     }  
  17.     public void setName(String name) {  
  18.         this.name = name;  
  19.     }  
  20.     public Set getUsers() {  
  21.         return users;  
  22.     }  
  23.     public void setUsers(Set users) {  
  24.         this.users = users;  
  25.     }  
  26. }  

User

  1. package com.liang.hibernate;  
  2.   
  3. public class User {  
  4.     private int id;  
  5.     private String name;  
  6.   
  7.     public int getId() {  
  8.         return id;  
  9.     }  
  10.     public void setId(int id) {  
  11.         this.id = id;  
  12.     }  
  13.     public String getName() {  
  14.         return name;  
  15.     }  
  16.     public void setName(String name) {  
  17.         this.name = name;  
  18.     }  
  19. }  

User.hbm.xml

  1. <?xml version="1.0"?>  
  2. <!DOCTYPE hibernate-mapping PUBLIC   
  3.     "-//Hibernate/Hibernate Mapping DTD 3.0//EN"  
  4.     "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">  
  5. <hibernate-mapping>  
  6.     <class name="com.liang.hibernate.User" table="t_user">  
  7.         <id name="id">  
  8.             <generator class="native"/>  
  9.         </id>  
  10.         <property name="name"/>  
  11.     </class>  
  12. </hibernate-mapping>  

Group.hbm.xml

  1. <?xml version="1.0"?>  
  2. <!DOCTYPE hibernate-mapping PUBLIC   
  3.     "-//Hibernate/Hibernate Mapping DTD 3.0//EN"  
  4.     "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">  
  5. <hibernate-mapping>  
  6.     <class name="com.liang.hibernate.Group" table="t_group">  
  7.         <id name="id">  
  8.             <generator class="native"/>  
  9.         </id>  
  10.         <property name="name"/>  
  11.         <!-- users屬性,表達的是本對象與User的一對多的關係 -->  
  12.         <set name="users">  
  13.              <!--當前表(Group)的主鍵-->  
  14.             <key column="groupid"/>  
  15.             <one-to-many class="com.liang.hibernate.User"/>  
  16.         </set>  
  17.     </class>  
  18. </hibernate-mapping>  

生成的表結構和測試數據

缺點

 

1)因爲多端User不知道Group的存在(也就是User不維護與Group的關係),所以在保存User時,關係字段groupId爲null,如果該字段設置爲非空,則將無法保存數據。

2)因爲User不維護關係,而Group維護關係,Group就會發出多餘的update語句,保證Group和User有關係,這樣加載Group時才把該Users對應的用戶加載上來。

 

一對多雙向關聯映射

 

對象模型

           

        雙向關聯映射對比單向關聯映射,對象的加載方向由單向變成了雙向。

 

我們看一下Group和User的實體,映射文件

Group

  1. package com.liang.hibernate;  
  2.   
  3. import java.util.Set;  
  4.   
  5. public class Group {  
  6.     private int id;  
  7.     private String name;  
  8.     private Set users;  
  9.   
  10.     public int getId() {  
  11.         return id;  
  12.     }  
  13.     public void setId(int id) {  
  14.         this.id = id;  
  15.     }  
  16.     public String getName() {  
  17.         return name;  
  18.     }  
  19.     public void setName(String name) {  
  20.         this.name = name;  
  21.     }  
  22.     public Set getUsers() {  
  23.         return users;  
  24.     }  
  25.     public void setUsers(Set users) {  
  26.         this.users = users;  
  27.     }  
  28. }  

User

  1. package com.liang.hibernate;  
  2.   
  3. public class User {  
  4.     private int id;  
  5.     private String name;  
  6.     private Group groups;  
  7.     public int getId() {  
  8.         return id;  
  9.     }  
  10.     public void setId(int id) {  
  11.         this.id = id;  
  12.     }  
  13.     public String getName() {  
  14.         return name;  
  15.     }  
  16.     public void setName(String name) {  
  17.         this.name = name;  
  18.     }  
  19.     public Group getGroups() {  
  20.         return groups;  
  21.     }  
  22.     public void setGroups(Group groups) {  
  23.         this.groups = groups;  
  24.     }  
  25. }  

Group.hbm.xml

  1. <?xml version="1.0"?>  
  2. <!DOCTYPE hibernate-mapping PUBLIC   
  3.     "-//Hibernate/Hibernate Mapping DTD 3.0//EN"  
  4.     "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">  
  5. <hibernate-mapping package="com.liang.hibernate">  
  6.     <class name="Group" table="t_group">  
  7.         <id name="id">  
  8.             <generator class="native"/>  
  9.         </id>  
  10.         <property name="name"/>  
  11.         <!-- 影響控制反轉:inverse="false",多的一端維護關係,讓一的一端失效 -->  
  12.         <set name="users" inverse="true">  
  13.             <key column="groupid" not-null="true"/>  
  14.             <one-to-many class="User"/>  
  15.         </set>  
  16.     </class>  
  17. </hibernate-mapping>  

User.hbm.xml

  1. <?xml version="1.0"?>  
  2. <!DOCTYPE hibernate-mapping PUBLIC   
  3.     "-//Hibernate/Hibernate Mapping DTD 3.0//EN"  
  4.     "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">  
  5. <hibernate-mapping package="com.liang.hibernate">  
  6.     <class name="User" table="t_user">  
  7.         <id name="id">  
  8.             <generator class="native"/>  
  9.         </id>  
  10.         <property name="name"/>  
  11.         <!-- groups屬性,表達的是本對象與Group的多對一的關係 -->  
  12.         <many-to-one name="groups" class="Group" column="groupid"/>  
  13.     </class>  
  14. </hibernate-mapping>  

生成的表和測試數據

 

一對多雙向關聯的映射方式:
 1)在一的一端的集合上採用<key>標籤,在多的一端加入一個外鍵
 2)在多的一端採用<many-to-one>標籤

注意:<key>標籤和<many-to-one>標籤加入的字段保持一直,否則會產生數據混亂。

inverse屬性:

         inverse屬性可以用在一對多和多對多雙向關聯上,inverse屬性默認爲false,爲false表示本端維護關係,如果inversetrue,則本端不能維護關係,會交給另一端維護關係,本端失效。所以一對多關聯映射我們通常在多的一端維護關係,讓一的一端失效,所以設置爲inversetrue。

注意:inverse屬性,隻影響數據的存儲,也就是持久化。

 

目的

 

       一對多雙向關聯映射的目的主要是爲了解決一對多單向關聯的缺陷而不是需求驅動的。

(五)多對多關聯映射


映射原理

 

     不論是單向關聯還是雙向關聯都是通過第三張表,將兩個表中的主鍵放到第三張做一個關聯。用第三張表來解決可能會造成數據冗餘的問題。

 

舉例

 

一個用戶(User)對多個角色(Role),一個角色對多個用戶。

 

分類

 

單向的多對多關聯映射(單向User--->Role)

 

對象模型

              

關係模型

            

 

實例

      下面我們看一下實體類和映射文件的代碼。

User

  1. package com.liang.hibernate;  
  2.   
  3. import java.util.Set;  
  4.   
  5. public class User {  
  6.     private int id;  
  7.     private String name;  
  8.       
  9.     private Set roles;  
  10.       
  11.     public int getId() {  
  12.         return id;  
  13.     }  
  14.     public void setId(int id) {  
  15.         this.id = id;  
  16.     }  
  17.     public Set getRoles() {  
  18.         return roles;  
  19.     }  
  20.     public void setRoles(Set roles) {  
  21.         this.roles = roles;  
  22.     }  
  23.     public String getName() {  
  24.         return name;  
  25.     }  
  26.     public void setName(String name) {  
  27.         this.name = name;  
  28.     }  
  29.       
  30. }  

Role

  1. package com.liang.hibernate;  
  2.   
  3. public class Role {  
  4.     private int id;  
  5.     private String name;  
  6.       
  7.     public int getId() {  
  8.         return id;  
  9.     }  
  10.     public void setId(int id) {  
  11.         this.id = id;  
  12.     }  
  13.     public String getName() {  
  14.         return name;  
  15.     }  
  16.     public void setName(String name) {  
  17.         this.name = name;  
  18.     }  
  19. }  

User.hbm.xml

  1. <?xml version="1.0"?>  
  2. <!DOCTYPE hibernate-mapping PUBLIC   
  3.     "-//Hibernate/Hibernate Mapping DTD 3.0//EN"  
  4.     "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">  
  5. <hibernate-mapping package="com.liang.hibernate">  
  6.     <class name="User" table="t_user">  
  7.         <id name="id">  
  8.             <generator class="native"></generator>  
  9.         </id>  
  10.         <property name="name"></property>  
  11.         <!-- roles屬性,表達的是本對象(User)與Role的多對多的關係 -->    
  12.         <set name="roles" table="t_user_role">  
  13.             <!--當前表(User)的主鍵-->  
  14.             <key column="user_id"></key>  
  15.             <many-to-many class="Role" column="role_id"></many-to-many>  
  16.         </set>  
  17.     </class>  
  18. </hibernate-mapping>  

Role.hbm.xml

  1. <?xml version="1.0"?>  
  2. <!DOCTYPE hibernate-mapping PUBLIC   
  3.     "-//Hibernate/Hibernate Mapping DTD 3.0//EN"  
  4.     "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">  
  5. <hibernate-mapping package="com.liang.hibernate">  
  6.     <class name="Role" table="t_role">  
  7.         <id name="id">  
  8.             <generator class="native"></generator>  
  9.         </id>  
  10.         <property name="name"></property>  
  11.     </class>  
  12. </hibernate-mapping>  

生成的表結構和測試數據

 

       多對多關聯映射,在實體類中,跟一對多關聯映射一樣,也是用集合來表示的。<set>標籤中用table屬性重命名中間表名稱,<key>標籤定義當前表的主鍵,用<many-to-many>標籤來關聯另一張表。

 

雙向的多對多關聯映射(雙向User<--->Role)

 

 

對象模型

             

關係模型

 

       同上

 

實例

      

     下面我們看一下實體類和映射文件的代碼。

User

  1. package com.liang.hibernate;  
  2. import java.util.Set;  
  3.   
  4. public class User {  
  5.     private int id;  
  6.     private String name;  
  7.       
  8.     private Set roles;  
  9.       
  10.     public int getId() {  
  11.         return id;  
  12.     }  
  13.     public void setId(int id) {  
  14.         this.id = id;  
  15.     }  
  16.     public Set getRoles() {  
  17.         return roles;  
  18.     }  
  19.     public void setRoles(Set roles) {  
  20.         this.roles = roles;  
  21.     }  
  22.     public String getName() {  
  23.         return name;  
  24.     }  
  25.     public void setName(String name) {  
  26.         this.name = name;  
  27.     }  
  28.       
  29. }  

Role

  1. package com.liang.hibernate;  
  2. import java.util.Set;  
  3. public class Role {  
  4.     private int id;  
  5.     private String name;  
  6.     private Set users;  
  7.       
  8.     public Set getUsers() {  
  9.         return users;  
  10.     }  
  11.     public void setUsers(Set users) {  
  12.         this.users = users;  
  13.     }  
  14.     public int getId() {  
  15.         return id;  
  16.     }  
  17.     public void setId(int id) {  
  18.         this.id = id;  
  19.     }  
  20.     public String getName() {  
  21.         return name;  
  22.     }  
  23.     public void setName(String name) {  
  24.         this.name = name;  
  25.     }  
  26. }  

User.hbm.xml

  1. <?xml version="1.0"?>  
  2. <!DOCTYPE hibernate-mapping PUBLIC   
  3.     "-//Hibernate/Hibernate Mapping DTD 3.0//EN"  
  4.     "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">  
  5. <hibernate-mapping package="com.liang.hibernate">  
  6.     <class name="User" table="t_user">  
  7.         <id name="id">  
  8.             <generator class="native"></generator>  
  9.         </id>  
  10.         <property name="name"></property>  
  11.         <!-- roles屬性,表達的是本對象(User)與Role的多對多的關係 -->    
  12.         <set name="roles" table="t_user_role">  
  13.             <!--當前表(User)的主鍵-->  
  14.             <key column="user_id"></key>  
  15.             <many-to-many class="Role" column="role_id"></many-to-many>  
  16.         </set>  
  17.     </class>  
  18. </hibernate-mapping>  

Role.hbm.xml

  1. <?xml version="1.0"?>  
  2. <!DOCTYPE hibernate-mapping PUBLIC   
  3.     "-//Hibernate/Hibernate Mapping DTD 3.0//EN"  
  4.     "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">  
  5. <hibernate-mapping package="com.liang.hibernate">  
  6.     <class name="Role" table="t_role">  
  7.         <id name="id">  
  8.             <generator class="native"></generator>  
  9.         </id>  
  10.         <property name="name"></property>  
  11.         <!-- users屬性,表達的是本對象(Role)與User的多對多的關係 -->    
  12.         <set name="users" table="t_user_role">  
  13.             <!--當前表(Role)的主鍵-->                  
  14.             <key column="role_id"></key>  
  15.             <many-to-many class="User" column="user_id"></many-to-many>  
  16.         </set>  
  17.     </class>  
  18. </hibernate-mapping>  

生成的表結構和測試數據

 

      多對多雙向關係中,User和Role的映射文件相同,值得注意的是生成的中間表名稱必須一樣,生成中間表的字段必須一樣。

 

總結

 

      多對多關聯映射到此就結束了,經過對一對多關聯映射的學習,相對而言,多對多關聯映射變得非常的簡單了,非常像一對多關聯映射的變體。

      Hibernate是一個對象關係映射框架,當然從分層的角度看,我們也說它是數據持久層的框架。

      我們從上一句話可以看出Hibernate的核心:面向對象、關係映射以及數據持久化。前面兩個概念很容易理解,而對於“數據持久化”,就是將數據或者某物體,永久的保存起來。現實生活中的例子有很多,例如:鮮肉冷藏,水果做成罐頭,而對於編程而言就是將數據保存在文件或磁盤以及數據庫中。下面我們再看一下Hibernate的核心對象:


核心對象

         

     上面這幅圖反饋給我們的信息有很多,能否讀懂這幅圖可以從側面反映你對Hibernate理解的水平。下面我們說幾條:

1、Hibernate有倆個主要的配置文件:(Hibernate.cfg.xml和xxx.hbm.xml)

2、Hibernate有五個或六個接口:Configuration、SessionFactory、Session、Transaction、Query和Criteria。

3、Hibernate的執行原理,看上圖的箭頭即可。

4、Session對象是通過SessionFactory構建的,這是Hibernate創建Session的兩種方式之一。

。。。。。。

 

      由於內容太多,我們暫時就列這麼多,就不再一一列舉了。下面我們再詳細的介紹映射的分類。

 

分類

       

        

      在Hibernate系列的起初,我將關係映射分爲了以上四種,現在來看關係映射其實就兩種,甚至一種

 

1、從對象的加載方向上分爲單向和雙向兩種。

      單向和雙向隻影響數據的加載,並不影響數據的存儲。不論是一對一,一對多還是多對多,單向和雙向生成的數據庫表是一樣,單向和雙向的不同是由對象模型決定的。

 

2、從對象的映射關係上分爲一對多和多對一兩種,它們又是從不同角度說的,所以也可以說是一種。

      一對一關聯映射是多對一關聯映射的特例,只是在“多”的一端加上唯一的限制之後,用來表示一對一的關聯關係。

      多對多關聯映射是一對多關聯映射的特例,它們呢都是使用集合來表示多的關係,用<key>標籤定義當前表的主鍵。

     當然它們既有聯繫也有區別,區別就不再一一列舉了,系列博文中已經詳細的介紹了各自的聯繫與區別。




      Hibernate是一個對象關係映射框架,當然從分層的角度看,我們也說它是數據持久層的框架。

      我們從上一句話可以看出Hibernate的核心:面向對象、關係映射以及數據持久化。前面兩個概念很容易理解,而對於“數據持久化”,就是將數據或者某物體,永久的保存起來。現實生活中的例子有很多,例如:鮮肉冷藏,水果做成罐頭,而對於編程而言就是將數據保存在文件或磁盤以及數據庫中。下面我們再看一下Hibernate的核心對象:


核心對象

         

     上面這幅圖反饋給我們的信息有很多,能否讀懂這幅圖可以從側面反映你對Hibernate理解的水平。下面我們說幾條:

1、Hibernate有倆個主要的配置文件:(Hibernate.cfg.xml和xxx.hbm.xml)

2、Hibernate有五個或六個接口:Configuration、SessionFactory、Session、Transaction、Query和Criteria。

3、Hibernate的執行原理,看上圖的箭頭即可。

4、Session對象是通過SessionFactory構建的,這是Hibernate創建Session的兩種方式之一。

。。。。。。

 

      由於內容太多,我們暫時就列這麼多,就不再一一列舉了。下面我們再詳細的介紹映射的分類。

 

分類

       

        

      在Hibernate系列的起初,我將關係映射分爲了以上四種,現在來看關係映射其實就兩種,甚至一種

 

1、從對象的加載方向上分爲單向和雙向兩種。

      單向和雙向隻影響數據的加載,並不影響數據的存儲。不論是一對一,一對多還是多對多,單向和雙向生成的數據庫表是一樣,單向和雙向的不同是由對象模型決定的。

 

2、從對象的映射關係上分爲一對多和多對一兩種,它們又是從不同角度說的,所以也可以說是一種。

      一對一關聯映射是多對一關聯映射的特例,只是在“多”的一端加上唯一的限制之後,用來表示一對一的關聯關係。

      多對多關聯映射是一對多關聯映射的特例,它們呢都是使用集合來表示多的關係,用<key>標籤定義當前表的主鍵。

     當然它們既有聯繫也有區別,區別就不再一一列舉了,系列博文中已經詳細的介紹了各自的聯繫與區別。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章