hibernate一對多單向和雙向映射

本文轉自:http://quicker.iteye.com/blog/657795

一、一對多單向關聯

多對一與一對多類似
一對多映射中,只需要在一方的POJO中加入Set.
在一方的映射中加入:
<set name="students">
 <key column="class_id"></key>
 <one-to-many class="Student"/>
</set>
起到指示作用,指示在多方的表中加入一個外鍵.

Java代碼  收藏代碼
  1. Hibernate一對多單向關聯映射  
  2.   
  3. 這種映射的本質是利用了多對一的關聯映射的原理  
  4.   
  5. 多對一關聯映射:是在多的一端添加一個外鍵維護多指向一的關聯引用  
  6. 一對多關聯映射:是在多的一端添加一個外鍵維護一指向多的關聯引用  
  7.   
  8. 也就是說,一對多和多對一的映射策略是一致的,只是站的角度不同  
  9.   
  10. 缺點:  
  11.   * 更新student表中的classesid字段時,需要對每一個student發出一個update的sql,  
  12.     來更新classesid字段  
  13.   * 如果將t_student表中的classesis設置爲非空,則不能保存student數據,因爲關係是由  
  14.     classes維護的,在保存student時,還沒有對應的classesid被生成     

 

 

具體示例如下:

Java代碼  收藏代碼
  1. package com.lwf.hibernate.pojo;  
  2.   
  3. import java.util.HashSet;  
  4. import java.util.Set;  
  5.   
  6. public class Classes {  
  7.   
  8.     private int id;  
  9.     private String name;  
  10.     private Set students = new HashSet();  
  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.     public Set getStudents() {  
  25.         return students;  
  26.     }  
  27.     public void setStudents(Set students) {  
  28.         this.students = students;  
  29.     }  
  30.       
  31. }  

 

Java代碼  收藏代碼
  1. package com.lwf.hibernate.pojo;  
  2.   
  3. public class Student {  
  4.   
  5.     private int id;  
  6.     private String name;  
  7.     private int age;  
  8.   
  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 int getAge() {  
  23.         return age;  
  24.     }  
  25.     public void setAge(int age) {  
  26.         this.age = age;  
  27.     }  
  28.       
  29. }  

 

Classes.hbm.xml

Java代碼  收藏代碼
  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.lwf.hibernate.pojo">  
  6.       
  7.         <class name="Classes" table="t_classes">  
  8.             <id name="id">  
  9.                 <generator class="native"/>  
  10.             </id>  
  11.             <property name="name"/>  
  12.             <set name="students" >  
  13.                 <key column="class_id" ></key>  
  14.                 <one-to-many class="Student" />  
  15.             </set>  
  16.               
  17.         </class>  
  18.     </hibernate-mapping>  

 Student.hbm.xml

Java代碼  收藏代碼
  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.lwf.hibernate.pojo">  
  6.         <class name="Student" table="t_student">  
  7.             <id name="id">  
  8.                 <generator class="native"/>  
  9.             </id>  
  10.             <property name="name"/>  
  11.             <property name="age"/>  
  12.               
  13.         </class>  
  14.           
  15.     </hibernate-mapping>  

  

具體的數據庫結構:

 

Java代碼  收藏代碼
  1. mysql> desc student;  
  2. +----------+--------------+------+-----+---------+----------------+  
  3. | Field    | Type         | Null | Key | Default | Extra          |  
  4. +----------+--------------+------+-----+---------+----------------+  
  5. | id       | int(11)      | NO   | PRI | NULL    | auto_increment |  
  6. | name     | varchar(255) | YES  |     | NULL    |                |  
  7. | class_id | int(11)      | YES  | MUL | NULL    |                |  
  8. +----------+--------------+------+-----+---------+----------------+  
  9. 3 rows in set (0.06 sec)  
  10.   
  11. mysql> desc t_class;  
  12. +-------+--------------+------+-----+---------+----------------+  
  13. | Field | Type         | Null | Key | Default | Extra          |  
  14. +-------+--------------+------+-----+---------+----------------+  
  15. | id    | int(11)      | NO   | PRI | NULL    | auto_increment |  
  16. | name  | varchar(255) | YES  |     | NULL    |                |  
  17. +-------+--------------+------+-----+---------+----------------+  

 

 測試方法:

Java代碼  收藏代碼
  1. package com.lwf.hibernate.test;  
  2.   
  3. import java.util.HashSet;  
  4. import java.util.Iterator;  
  5. import java.util.Set;  
  6.   
  7. import junit.framework.TestCase;  
  8.   
  9. import org.hibernate.Session;  
  10.   
  11. import com.lwf.hibernate.pojo.Classes;  
  12. import com.lwf.hibernate.pojo.Student;  
  13. import com.lwf.hibernate.util.HibernateUtil;  
  14.   
  15. public class One2Many_Test extends TestCase{  
  16.   
  17.     //從classes這一端來維護,即在單方維護,會產生insert和update語句.  
  18.     public void testClasses(){  
  19.         Session session = HibernateUtil.getSession();  
  20.         session.beginTransaction();  
  21.         try{  
  22.               
  23.             Set students = new HashSet();  
  24.             for(int i=0;i<5;i++){  
  25.                 Student s = new Student();  
  26.                 s.setName("name" + i);  
  27.                 s.setAge((10 + i));  
  28.                 students.add(s);  
  29.                 session.save(s);  
  30.             }  
  31.               
  32.               
  33.             Classes cla = new Classes();  
  34.             cla.setName("class1");  
  35.             cla.setStudents(students);  
  36.             session.save(cla);  
  37.             //先保存,最後根據class_id更新Student  
  38.               
  39.             HibernateUtil.commit(session);  
  40.         }catch(Exception e){  
  41.             HibernateUtil.roolback(session);  
  42.         }finally{  
  43.             HibernateUtil.closeSession(session);  
  44.         }  
  45.     }  
  46.       
  47.       
  48.     public void testLoad(){  
  49.         Session session = HibernateUtil.getSession();  
  50.         session.beginTransaction();  
  51.         try{  
  52.             Classes s = (Classes)session.load(Classes.class1);  
  53.             Set student = s.getStudents();  
  54.             for (Iterator iterator = student.iterator(); iterator.hasNext();) {  
  55.                 Student stu = (Student) iterator.next();  
  56.                 System.out.println(stu.getName());  
  57.             }  
  58.             HibernateUtil.commit(session);  
  59.         }catch(Exception e){  
  60.             HibernateUtil.roolback(session);  
  61.         }finally{  
  62.             HibernateUtil.closeSession(session);  
  63.         }  
  64.     }  
  65.       
  66.       
  67. }  

 

 

注意保存生成的語句:

Java代碼  收藏代碼
  1. Hibernate: insert into t_student (name, age) values (?, ?)  
  2. Hibernate: insert into t_student (name, age) values (?, ?)  
  3. Hibernate: insert into t_student (name, age) values (?, ?)  
  4. Hibernate: insert into t_student (name, age) values (?, ?)  
  5. Hibernate: insert into t_student (name, age) values (?, ?)  
  6. Hibernate: insert into t_classes (name) values (?)  
  7. Hibernate: update t_student set class_id=? where id=?  
  8. Hibernate: update t_student set class_id=? where id=?  
  9. Hibernate: update t_student set class_id=? where id=?  
  10. Hibernate: update t_student set class_id=? where id=?  
  11. Hibernate: update t_student set class_id=? where id=?  

 

先保存student,再保存classes最後根據classes的id更新student的class_id

這實際上是由classes這方來維護兩者的關聯關係.

正常情況下關係應該由多的一方來維護,在雙向關聯中我們從多方來維護兩者的關係.這樣就可以避免update語句的出現.而是直接insert即可.

 

二、一對多雙向關聯

 

下面我們看看雙向的一對多映射,實際上就是把一對多與多對一結合起來看.

Java代碼  收藏代碼
  1. Hibernate 一對多雙向關聯映射  
  2.   
  3. 一對多雙向關聯映射的方法:  
  4.   
  5. 在一一端:  
  6. 在集合標籤裏面使用<key>標籤來表明需要在對方的表中添加一個外鍵指向一一端。  
  7.   
  8. 在多一端:  
  9. 使用<many-to-one>標籤來映射。  
  10.   
  11. 需要注意:<key>標籤所指定的外鍵字段名需要與<many-to-one>標籤定義的外鍵字段名一致,否則便會造成引用數據的  
  12. 丟失!  
  13.   
  14. --------------------------------------------------------------------------------------  
  15. 如果從一端來維護一對多雙向關聯的關係,hibernate會發出多餘的update語句,所以  
  16. 一般地情況下,我們便會從多一端來維護其關聯關係!  
  17. ----------------------------------------------------  

  

 

 在單向映射的基礎上加上多對一關聯即可.更改的文件:

Java代碼  收藏代碼
  1. package com.lwf.hibernate.pojo;  
  2.   
  3. public class Student {  
  4.   
  5.     private int id;  
  6.     private String name;  
  7.     private int age;  
  8.     private Classes classes;  
  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 int getAge() {  
  23.         return age;  
  24.     }  
  25.     public void setAge(int age) {  
  26.         this.age = age;  
  27.     }  
  28.     public Classes getClasses() {  
  29.         return classes;  
  30.     }  
  31.     public void setClasses(Classes classes) {  
  32.         this.classes = classes;  
  33.     }  
  34.       
  35. }  

 

Student.hbm.xml

Java代碼  收藏代碼
  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.lwf.hibernate.pojo">  
  6.         <class name="Student" table="t_student">  
  7.             <id name="id">  
  8.                 <generator class="native"/>  
  9.             </id>  
  10.             <property name="name"/>  
  11.             <property name="age"/>  
  12.             <many-to-one name="classes" column="class_id"></many-to-one>  
  13.         </class>  
  14.           
  15.     </hibernate-mapping>  

 

即從Student的角度就是多對一,而從Classes角度就是一對多.

此時的表結構與單向的時候是一樣的.

Java代碼  收藏代碼
  1. package com.lwf.hibernate.test;  
  2.   
  3. import java.util.HashSet;  
  4. import java.util.Iterator;  
  5. import java.util.Set;  
  6.   
  7. import junit.framework.TestCase;  
  8.   
  9. import org.hibernate.Session;  
  10.   
  11. import com.lwf.hibernate.pojo.Classes;  
  12. import com.lwf.hibernate.pojo.Student;  
  13. import com.lwf.hibernate.util.HibernateUtil;  
  14.   
  15. public class One2Many_Test extends TestCase{  
  16.   
  17.     //從classes這一端來維護,即在單方維護,會產生insert和update語句.  
  18.     public void testClasses(){  
  19.         Session session = HibernateUtil.getSession();  
  20.         session.beginTransaction();  
  21.         try{  
  22.               
  23.             Set students = new HashSet();  
  24.             for(int i=0;i<5;i++){  
  25.                 Student s = new Student();  
  26.                 s.setName("name" + i);  
  27.                 s.setAge((10 + i));  
  28.                 students.add(s);  
  29.                 session.save(s);  
  30.             }  
  31.               
  32.               
  33.             Classes cla = new Classes();  
  34.             cla.setName("class1");  
  35.             cla.setStudents(students);  
  36.             session.save(cla);  
  37.             //先保存,最後根據class_id更新Student  
  38.               
  39.             HibernateUtil.commit(session);  
  40.         }catch(Exception e){  
  41.             HibernateUtil.roolback(session);  
  42.         }finally{  
  43.             HibernateUtil.closeSession(session);  
  44.         }  
  45.     }  
  46.       
  47.       
  48.     //由於配置了雙向關聯,所以下面先保存了classes再保存student只有insert語句,沒有update語句  
  49.     public void testStudent(){  
  50.         Session session = HibernateUtil.getSession();  
  51.         session.beginTransaction();  
  52.         try{  
  53.             Classes cla = new Classes();  
  54.             cla.setName("class111");  
  55.             session.save(cla);  
  56.             for (int i = 0; i < 5; i++) {  
  57.                 Student s  = new Student();  
  58.                 s.setName("name111"+i);  
  59.                 s.setClasses(cla);  
  60.                 session.save(s);  
  61.             }  
  62.             HibernateUtil.commit(session);  
  63.         }catch(Exception e){  
  64.             HibernateUtil.roolback(session);  
  65.         }finally{  
  66.             HibernateUtil.closeSession(session);  
  67.         }  
  68.               
  69.     }  
  70.       
  71.     //從classes得到student,主要測試單向關聯  
  72.     public void testLoadClass(){  
  73.         Session session = HibernateUtil.getSession();  
  74.         session.beginTransaction();  
  75.         try{  
  76.             Classes s = (Classes)session.load(Classes.class1);  
  77.             Set student = s.getStudents();  
  78.             for (Iterator iterator = student.iterator(); iterator.hasNext();) {  
  79.                 Student stu = (Student) iterator.next();  
  80.                 System.out.println(stu.getName());  
  81.             }  
  82.             HibernateUtil.commit(session);  
  83.         }catch(Exception e){  
  84.             HibernateUtil.roolback(session);  
  85.         }finally{  
  86.             HibernateUtil.closeSession(session);  
  87.         }  
  88.     }  
  89.       
  90.     //從student得到classes,配置了雙向關聯後的測試  
  91.     public void testLoadStudent(){  
  92.         Session session = HibernateUtil.getSession();  
  93.         session.beginTransaction();  
  94.         try{  
  95.             Student s = (Student)session.load(Student.class1);  
  96.             System.out.println(s.getName());  
  97.             System.out.println(s.getClasses().getName());  
  98.             HibernateUtil.commit(session);  
  99.         }catch(Exception e){  
  100.             HibernateUtil.roolback(session);  
  101.         }finally{  
  102.             HibernateUtil.closeSession(session);  
  103.         }  
  104.     }  
  105.       
  106.       
  107. }  

主要區別:

由於配置了雙向關聯,所以下面先保存了classes再保存student只有insert語句,沒有update語句

以下是testStudent方法產生的SQL語句

Java代碼  收藏代碼
  1. Hibernate: insert into t_classes (name) values (?)  
  2. Hibernate: insert into t_student (name, age, class_id) values (?, ?, ?)  
  3. Hibernate: insert into t_student (name, age, class_id) values (?, ?, ?)  
  4. Hibernate: insert into t_student (name, age, class_id) values (?, ?, ?)  
  5. Hibernate: insert into t_student (name, age, class_id) values (?, ?, ?)  
  6. Hibernate: insert into t_student (name, age, class_id) values (?, ?, ?)  

 

 

 

三、下面討論一下關於INVERSE的用法:

Java代碼  收藏代碼
  1. 關於inverse屬性:  
  2. inverse屬性可以被設置到集合標籤<set>上,表示在存儲雙向一對多關聯映射的時候,  
  3. 存儲的是那一方的關聯引用。默認情況下,inverse=“false”,所以,我們可以從一一端  
  4. 或者多一端來維護兩者之間的關係;如果我們設置inverse=“true”,則只能通過多一端來  
  5. 維護兩者之間的關係。inverse屬性可以被用在一對多和多對多雙向關聯中;  
  6.   
  7. 注意:inverse屬性只是在將數據持久化到數據庫的過程中發揮作用.  

 

主要看看上面雙向關聯中testClasses方法,當classes.hbm.xml文件如下時

Java代碼  收藏代碼
  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.lwf.hibernate.pojo">  
  6.       
  7.         <class name="Classes" table="t_classes">  
  8.             <id name="id">  
  9.                 <generator class="native"/>  
  10.             </id>  
  11.             <property name="name"/>  
  12.             <set name="students" >  
  13.                 <key column="class_id" ></key>  
  14.                 <one-to-many class="Student" />  
  15.             </set>  
  16.               
  17.         </class>  
  18.     </hibernate-mapping>  

 我們知道上面的testClasses方法產生的sql語句是先insert再update,上面已經講到是從一方來維護關聯關係的.那麼現在我們把classes.hbm.xml的set上面增加inverse="true"即

Java代碼  收藏代碼
  1. <set name="students" inverse="true">  
  2.     <key column="class_id" ></key>  
  3.     <one-to-many class="Student" />  
  4. </set>  
  5.               

 那麼這時候testClasses方法產生的SQL語句是?

Java代碼  收藏代碼
  1. Hibernate: insert into t_student (name, age, class_id) values (?, ?, ?)  
  2. Hibernate: insert into t_student (name, age, class_id) values (?, ?, ?)  
  3. Hibernate: insert into t_student (name, age, class_id) values (?, ?, ?)  
  4. Hibernate: insert into t_student (name, age, class_id) values (?, ?, ?)  
  5. Hibernate: insert into t_student (name, age, class_id) values (?, ?, ?)  
  6. Hibernate: insert into t_classes (name) values (?)  

 

雖然只產生了insert語句,但因爲t_classes插入語句在後,所以數據庫裏面對應的t_student的記錄:

Java代碼  收藏代碼
  1. mysql> select * from t_student;  
  2. +----+-------+------+----------+  
  3. | id | name  | age  | class_id |  
  4. +----+-------+------+----------+  
  5. |  1 | name0 |   10 |     NULL |  
  6. |  2 | name1 |   11 |     NULL |  
  7. |  3 | name2 |   12 |     NULL |  
  8. |  4 | name3 |   13 |     NULL |  
  9. |  5 | name4 |   14 |     NULL |  
  10. +----+-------+------+----------+  

 顯然class_id爲空.沒有更新.

即用了INVERSE,將強制要求從多的一方來維護關係.即當設置了INVERSE屬性後,要求使用testStudent方法來做保存.

而INVERSE屬性沒有設置時,對於雙向的一對多關聯,我們即可以使用testClasses又可以使用testStudent方法進行保存,但是他們的區別是testClasses操作中有insert和update語句,而testStudent只有insert語句.顯然使用testStudent即從多方來維護關聯關係節約了資源...

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