hibernate一对多单向和双向映射配置实例源码说明

hibernate一对多单向和双向映射配置实例源码说明,一对多单向和双向映射。

一、hibernate一对多单向关联

hibernate中多对一和一对多类似
一对多映射中,只需要在一方的POJO中加入Set.
在一方的映射中加入:
<set name=”students”>
<key column=”class_id”></key>
<one-to-many/>
</set>
有指示作用,指示在多方的表中加入一个外键.

Java代码  收藏代码
  1. Hibernate一对多单向关联映射
  2. hibernate这种映射的本质是利用了多对一的关联映射的原理
  3. 多对一关联映射:是在多的一端添加一个外键维护多指向一的关联引用
  4. 一对多关联映射:是在多的一端添加一个外键维护一指向多的关联引用
  5. 一对多和多对一的映射策略是一致的,只是站的角度不同
  6. 缺点:
  7.   * 更新student表中的classesid字段时,需要对每一个student发出一个update的sql,
  8.     来更新classesid字段
  9.   * 如果将t_student表中的classesis设置为非空,则不能保存student数据,因为关系是由
  10.     classes维护的,在保存student时,还没有对应的classesid被生成

具体实例代码如下:

Java代码  收藏代码
  1. package com.lwf.hibernate.pojo;
  2. import java.util.HashSet;
  3. import java.util.Set;
  4. public class Classes {
  5.     private int id;
  6.     private String name;
  7.     private Set students = new HashSet();
  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 getStudents() {
  21.         return students;
  22.     }
  23.     public void setStudents(Set students) {
  24.         this.students = students;
  25.     }
  26. }

 

Java代码  收藏代码
  1. package com.lwf.hibernate.pojo;
  2. public class Student {
  3.     private int id;
  4.     private String name;
  5.     private int age;
  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 int getAge() {
  19.         return age;
  20.     }
  21.     public void setAge(int age) {
  22.         this.age = age;
  23.     }
  24. }

 

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.         <class name=”Classes” table=”t_classes”>
  7.             <id name=”id”>
  8.                 <generator class=”native”/>
  9.             </id>
  10.             <property name=”name”/>
  11.             <set name=”students” >
  12.                 <key column=”class_id” ></key>
  13.                 <one-to-many class=”Student” />
  14.             </set>
  15.         </class>
  16.     </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.         </class>
  13.     </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. mysql> desc t_class;
  11. +——-+————–+——+—–+———+—————-+
  12. | Field | Type         | Null | Key | Default | Extra          |
  13. +——-+————–+——+—–+———+—————-+
  14. | id    | int(11)      | NO   | PRI | NULL    | auto_increment |
  15. | name  | varchar(255) | YES  |     | NULL    |                |
  16. +——-+————–+——+—–+———+—————-+

 

测试方法:

Java代码  收藏代码
  1. package com.lwf.hibernate.test;
  2. import java.util.HashSet;
  3. import java.util.Iterator;
  4. import java.util.Set;
  5. import junit.framework.TestCase;
  6. import org.hibernate.Session;
  7. import com.lwf.hibernate.pojo.Classes;
  8. import com.lwf.hibernate.pojo.Student;
  9. import com.lwf.hibernate.util.HibernateUtil;
  10. public class One2Many_Test extends TestCase{
  11.     //从classes这一端来维护,即在单方维护,会产生insert和update语句.
  12.     public void testClasses(){
  13.         Session session = HibernateUtil.getSession();
  14.         session.beginTransaction();
  15.         try{
  16.             Set students = new HashSet();
  17.             for(int i=0;i<5;i++){
  18.                 Student s = new Student();
  19.                 s.setName(“name” + i);
  20.                 s.setAge((10 + i));
  21.                 students.add(s);
  22.                 session.save(s);
  23.             }
  24.             Classes cla = new Classes();
  25.             cla.setName(“class1″);
  26.             cla.setStudents(students);
  27.             session.save(cla);
  28.             //先保存,最后根据class_id更新Student
  29.             HibernateUtil.commit(session);
  30.         }catch(Exception e){
  31.             HibernateUtil.roolback(session);
  32.         }finally{
  33.             HibernateUtil.closeSession(session);
  34.         }
  35.     }
  36.     public void testLoad(){
  37.         Session session = HibernateUtil.getSession();
  38.         session.beginTransaction();
  39.         try{
  40.             Classes s = (Classes)session.load(Classes.class, 1);
  41.             Set student = s.getStudents();
  42.             for (Iterator iterator = student.iterator(); iterator.hasNext();) {
  43.                 Student stu = (Student) iterator.next();
  44.                 System.out.println(stu.getName());
  45.             }
  46.             HibernateUtil.commit(session);
  47.         }catch(Exception e){
  48.             HibernateUtil.roolback(session);
  49.         }finally{
  50.             HibernateUtil.closeSession(session);
  51.         }
  52.     }
  53. }

 

注意保存生成的hibernate语句:

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. 在集合标签里面使用<key>标签来表明需要在对方的表中添加一个外键指向一一端。
  5. 在多一端:
  6. 使用<many-to-one>标签来映射。
  7. 需要注意:<key>标签所指定的外键字段名需要与<many-to-one>标签定义的外键字段名一致,否则便会造成引用数据的
  8. 丢失!
  9. ————————————————————————————–
  10. 如果从一端来维护一对多双向关联的关系,hibernate会发出多余的update语句,所以
  11. 一般地情况下,我们便会从多一端来维护其关联关系!
  12. ----------------------------------------------------

 

在单向映射的基础上加上多对一关联即可.更改的文件:

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

 

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.     </hibernate-mapping>

 

即从Student的角度就是多对一,而从Classes角度就是一对多.

此时的表结构与单向的时候是一样的.

Java代码  收藏代码
  1. package com.lwf.hibernate.test;
  2. import java.util.HashSet;
  3. import java.util.Iterator;
  4. import java.util.Set;
  5. import junit.framework.TestCase;
  6. import org.hibernate.Session;
  7. import com.lwf.hibernate.pojo.Classes;
  8. import com.lwf.hibernate.pojo.Student;
  9. import com.lwf.hibernate.util.HibernateUtil;
  10. public class One2Many_Test extends TestCase{
  11.     //从classes这一端来维护,即在单方维护,会产生insert和update语句.
  12.     public void testClasses(){
  13.         Session session = HibernateUtil.getSession();
  14.         session.beginTransaction();
  15.         try{
  16.             Set students = new HashSet();
  17.             for(int i=0;i<5;i++){
  18.                 Student s = new Student();
  19.                 s.setName(“name” + i);
  20.                 s.setAge((10 + i));
  21.                 students.add(s);
  22.                 session.save(s);
  23.             }
  24.             Classes cla = new Classes();
  25.             cla.setName(“class1″);
  26.             cla.setStudents(students);
  27.             session.save(cla);
  28.             //先保存,最后根据class_id更新Student
  29.             HibernateUtil.commit(session);
  30.         }catch(Exception e){
  31.             HibernateUtil.roolback(session);
  32.         }finally{
  33.             HibernateUtil.closeSession(session);
  34.         }
  35.     }
  36.     //由于配置了双向关联,所以下面先保存了classes再保存student只有insert语句,没有update语句
  37.     public void testStudent(){
  38.         Session session = HibernateUtil.getSession();
  39.         session.beginTransaction();
  40.         try{
  41.             Classes cla = new Classes();
  42.             cla.setName(“class111″);
  43.             session.save(cla);
  44.             for (int i = 0; i < 5; i++) {
  45.                 Student s  = new Student();
  46.                 s.setName(“name111″+i);
  47.                 s.setClasses(cla);
  48.                 session.save(s);
  49.             }
  50.             HibernateUtil.commit(session);
  51.         }catch(Exception e){
  52.             HibernateUtil.roolback(session);
  53.         }finally{
  54.             HibernateUtil.closeSession(session);
  55.         }
  56.     }
  57.     //从classes得到student,主要测试单向关联
  58.     public void testLoadClass(){
  59.         Session session = HibernateUtil.getSession();
  60.         session.beginTransaction();
  61.         try{
  62.             Classes s = (Classes)session.load(Classes.class, 1);
  63.             Set student = s.getStudents();
  64.             for (Iterator iterator = student.iterator(); iterator.hasNext();) {
  65.                 Student stu = (Student) iterator.next();
  66.                 System.out.println(stu.getName());
  67.             }
  68.             HibernateUtil.commit(session);
  69.         }catch(Exception e){
  70.             HibernateUtil.roolback(session);
  71.         }finally{
  72.             HibernateUtil.closeSession(session);
  73.         }
  74.     }
  75.     //从student得到classes,配置了双向关联后的测试
  76.     public void testLoadStudent(){
  77.         Session session = HibernateUtil.getSession();
  78.         session.beginTransaction();
  79.         try{
  80.             Student s = (Student)session.load(Student.class, 1);
  81.             System.out.println(s.getName());
  82.             System.out.println(s.getClasses().getName());
  83.             HibernateUtil.commit(session);
  84.         }catch(Exception e){
  85.             HibernateUtil.roolback(session);
  86.         }finally{
  87.             HibernateUtil.closeSession(session);
  88.         }
  89.     }
  90. }

主要区别:

由于配置了双向关联,所以下面先保存了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. 注意: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.         <class name=”Classes” table=”t_classes”>
  7.             <id name=”id”>
  8.                 <generator class=”native”/>
  9.             </id>
  10.             <property name=”name”/>
  11.             <set name=”students” >
  12.                 <key column=”class_id” ></key>
  13.                 <one-to-many class=”Student” />
  14.             </set>
  15.         </class>
  16.     </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>

那么这时候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即从多方来维护关联关系节约了资源...

本文链接地址: hibernate一对多单向和双向映射配置实例源码说明