`

hibernate 一对多(one-to-many)双向关联

 
阅读更多

一对多(one-to-many)双向关联实例(Department- Employee)

这里的一对多双向关联是在域模型(实体对象模型)上的概念,在关系数据库中,只存在外键参照关系,而且总是由"many"方参照"one"方,因为这样才能消除冗余数据,因上关系数据库实际上只支持多对一或一对一的单向关联.在实体(类与类之间)各种各样的关系中,数多对一的的单向关联关系与数据库中的外键参照关系最匹配了.

在我的前一篇文章多对一的基础上进行修改。

1.修改Department实体类:

Java代码 复制代码 收藏代码
  1. package com.reiyen.hibernate.domain   
  2. public class Department {   
  3.   
  4.     private int id;   
  5.     private String name;   
  6.     private Set<Employee> emps;    
  7.   
  8.    //setter和getter方法   
  9. }  
package com.reiyen.hibernate.domain
public class Department {

	private int id;
	private String name;
	private Set<Employee> emps; 

   //setter和getter方法
}

 2.修改Department.hbm.xml文件:

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.reiyen.hibernate.domain">  
  6.     <class name="Department" >  
  7.         <id name="id" >  
  8.             <generator class="native" />  
  9.         </id>  
  10.         <property name="name" />  
  11.         <set name="emps">  
  12.         <key column="depart_id" />  
  13.         <one-to-many class="Employee"/>  
  14.         </set>  
  15.     </class>  
  16. </hibernate-mapping>  
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC 
	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.reiyen.hibernate.domain">
	<class name="Department" >
		<id name="id" >
			<generator class="native" />
		</id>
		<property name="name" />
		<set name="emps">
		<key column="depart_id" />
		<one-to-many class="Employee"/>
		</set>
	</class>
</hibernate-mapping>

<set>元素的属性name:设定待映射的持久化类的属性名,这里为Depatment类的emps属性.

<set>元素的两个子元素:

<key>:设定与所关联的持久化类对应的表的外键,此处为Employee表的depart_id字段.

<one-to-many>:设定所关联的持久化类,此处为Employee.

Hibernate根椐以上配置信息获得如下信息:

<set>元素表明Department类的emps属性为java.util.Set集合类型.

<class>子元素表明emps集合中存放的是一组Employee对象

<key>子元素表明employee表是通过外键depart_id参照department表的.

 

 3. 其余的保持原样,测试类如下:

Java代码 复制代码 收藏代码
  1. public class Many2One {   
  2.   
  3.     /**  
  4.      * @param args  
  5.      */  
  6.     public static void main(String[] args) {   
  7.         Department depart = add();   
  8.         Department department = queryDepart(depart.getId());   
  9.                 //department.getEmps();3   
  10. // System.out.println("emp size:" + department.getEmps().size());4     
  11.     }   
  12.   
  13.     static Department queryDepart(int departId) {   
  14.         Session s = null;   
  15.         Transaction tx = null;   
  16.         try {   
  17.             s = HibernateUtil.getSession();   
  18.             tx = s.beginTransaction();   
  19.             Department depart = (Department) s.get(Department.class, departId);   
  20.              System.out.println("emp size:" + depart.getEmps().size());//1         
  21.                          // System.out.println("emps class:" + depart.getEmps().getClass());   //2    
  22.                          // Hibernate.initialize(depart.getEmps());   
  23.             tx.commit();   
  24.             return depart;   
  25.         } finally {   
  26.             if (s != null)   
  27.                 s.close();   
  28.         }   
  29.     }   
  30.   
  31.     static Department add() {   
  32.         Session s = null;   
  33.         Transaction tx = null;   
  34.         try {   
  35.             Department depart = new Department();   
  36.             depart.setName("department name");   
  37.                
  38.             Employee employee1 = new Employee();   
  39.             employee1.setDepartment(depart); // 对象模型:建立两个对象的关联    
  40.             employee1.setName("employee1 name2");   
  41.                
  42.             Employee employee2 = new Employee();   
  43.             employee2.setDepartment(depart); // 对象模型:建立两个对象的关联    
  44.             employee2.setName("employee2 name2");   
  45.   
  46.        // Set<Employee> set = new HashSet<Employee>();   
  47.             //    set.add(employee1);   
  48.             //  set.add(employee2);   
  49.             //  depart.setEmps(set);   
  50.                
  51.             s = HibernateUtil.getSession();   
  52.             tx = s.beginTransaction();   
  53.             s.save(depart);   
  54.             s.save(employee1);   
  55.             s.save(employee2);   
  56.             tx.commit();   
  57.             return depart;   
  58.         } finally {   
  59.             if (s != null)   
  60.                 s.close();   
  61.         }   
  62.     }   
  63. }  
public class Many2One {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		Department depart = add();
		Department department = queryDepart(depart.getId());
                //department.getEmps();3
// System.out.println("emp size:" + department.getEmps().size());4  
	}

	static Department queryDepart(int departId) {
		Session s = null;
		Transaction tx = null;
		try {
			s = HibernateUtil.getSession();
			tx = s.beginTransaction();
			Department depart = (Department) s.get(Department.class, departId);
			 System.out.println("emp size:" + depart.getEmps().size());//1      
                         // System.out.println("emps class:" + depart.getEmps().getClass());   //2 
                         // Hibernate.initialize(depart.getEmps());
			tx.commit();
			return depart;
		} finally {
			if (s != null)
				s.close();
		}
	}

	static Department add() {
		Session s = null;
		Transaction tx = null;
		try {
			Department depart = new Department();
			depart.setName("department name");
			
			Employee employee1 = new Employee();
			employee1.setDepartment(depart); // 对象模型:建立两个对象的关联 
			employee1.setName("employee1 name2");
			
			Employee employee2 = new Employee();
			employee2.setDepartment(depart); // 对象模型:建立两个对象的关联 
			employee2.setName("employee2 name2");

       // Set<Employee> set = new HashSet<Employee>();
		    //    set.add(employee1);
		    //	set.add(employee2);
		    //	depart.setEmps(set);
			
			s = HibernateUtil.getSession();
			tx = s.beginTransaction();
			s.save(depart);
			s.save(employee1);
			s.save(employee2);
			tx.commit();
			return depart;
		} finally {
			if (s != null)
				s.close();
		}
	}
}

 控制台打印信息如下:

Hibernate: insert into Department (name) values (?)
Hibernate: insert into Employee (name, depart_id) values (?, ?)
Hibernate: insert into Employee (name, depart_id) values (?, ?)
Hibernate: select department0_.id as id1_0_, department0_.name as name1_0_ from Department department0_ where department0_.id=?
Hibernate: select emps0_.depart_id as depart3_1_, emps0_.id as id1_, emps0_.id as id2_0_, emps0_.name as name2_0_, emps0_.depart_id as depart3_2_0_ from Employee emps0_ where emps0_.depart_id=?

emp size:2

数据库中记录如下所示:

mysql> select * from employee;
+----+-----------------+-----------+
| id | name            | depart_id |
+----+-----------------+-----------+
|  1 | employee1 name2 |         1 |
|  2 | employee2 name2 |         1 |
+----+-----------------+-----------+
2 rows in set (0.00 sec)

mysql> select * from department;
+----+-----------------+
| id | name            |
+----+-----------------+
|  1 | department name |
+----+-----------------+
1 row in set (0.00 sec)

 

虽然对象模型修改了,但数据库关系模型并没有改变。

 

如果把测试程序中注释部分去掉,同时将注释为“建立对象模型”这两句程序注释掉,虽然也能正确运行,但控制台会多打印出两条更新语句,说明数据库多执行了两次更新操作,效率上有影响,如下所示:

Hibernate: insert into Department (name) values (?)
Hibernate: insert into Employee (name, depart_id) values (?, ?)
Hibernate: insert into Employee (name, depart_id) values (?, ?)
Hibernate: update Employee set depart_id=? where id=?
Hibernate: update Employee set depart_id=? where id=?

Hibernate: select department0_.id as id1_0_, department0_.name as name1_0_ from Department department0_ where department0_.id=?
Hibernate: select emps0_.depart_id as depart3_1_, emps0_.id as id1_, emps0_.id as id2_0_, emps0_.name as name2_0_, emps0_.depart_id as depart3_2_0_ from Employee emps0_ where emps0_.depart_id=?
emp size:2

 

4.懒加载分析:

(1)如果将程序中标记为1的程序注释掉,控制台打印信息如下:

Hibernate: select department0_.id as id0_0_, department0_.name as name0_0_ from Department department0_ where department0_.id=?

此时只是将Department对象查询出来了,而对应的Employee并没有进行查询。

(2)如果将程序中标记为1的程序注释掉,同时将标记为2的前面的注释去掉,运行程序,控制台打印信息如下:

Hibernate: select department0_.id as id0_0_, department0_.name as name0_0_ from Department department0_ where department0_.id=?
emps class:class org.hibernate.collection.PersistentSet

此时可以看到其实Hibernate将hashset替换成了它自己写的PersistentSet,所以才能实现懒加载功能。同时可以发现当调用department.getEmps();hibernate只是获取了集合代理对象的引用,它并没有去查询数据库来填充集合对象。你还可以进一步测试来验证这个问题。如果你 将程序中标记为1的程序注释掉,同时去掉标记为3的语句前面的注释,你会发现程序能正常运行,但如果去掉标记为4的语句前面的注释,运行程序,则会抛出如下异常:

 org.hibernate.LazyInitializationException : failed to lazily initialize a collection of role: com.reiyen.hibernate.domain.Department.emps, no session or session was closed

(3)当进行department对象查询时,从department的表结构中也不能判断这个Department对象是否有对应的Employee,那为什么它不像一对一查询时,也一次性把相关联的对象查询出来呢??这是因为如果将关联的对象查询出来的话,因为数据较多,它会严重影响效率,而不像一对一时,反正从对象只有一个,一次性查询出来影响也不是太大,所以hibernate就假定你有相对应的Employee,直接创建了一个集合代理对象的返回给你(把对象引用先给你),等你需要数据的时候再去查询数据库,以提高效率!

分享到:
评论

相关推荐

    hibernate学习5之one-to-many双向关联.docx

    如果在”一“一端维护一对多关联关系,hibernate会发出多余的udpate语句,所以我们一般在多的一端来维护关联关系。 加上inverse="true"这个属性,就可以强制在多的一端维护关系了。

    Hibernate学习笔记

    020 &lt;one-to-one&gt;、&lt;many-to-one&gt;单端关联上的 lazy(懒加载)属性 021 继承关联映射 022 component(组件)关联映射 023 复合主键 关联映射 024 其它 关联映射 025 hibernate 悲观锁、乐观锁 026 hibernate 操作树形...

    hibernate学习笔记

    hibernate一对多双向自连接关联映射 15 hibernate多对多关联映射(单向User----&gt;Role) 19 hibernate多对多关联映射(双向User&lt;----&gt;Role) 20 Hibernate的继承关系 21 每棵继承树映射成一张表(hibernate_extends_1) 22 ...

    HibernateAPI中文版.chm

    6.2.5. 一对多关联(One-to-many Associations) 6.3. 高级集合映射(Advanced collection mappings) 6.3.1. 有序集合(Sorted collections) 6.3.2. 双向关联(Bidirectional associations) 6.3.3. 双向关联...

    hibernate3.2中文文档(chm格式)

    6.2.5. 一对多关联(One-to-many Associations) 6.3. 高级集合映射(Advanced collection mappings) 6.3.1. 有序集合(Sorted collections) 6.3.2. 双向关联(Bidirectional associations) 6.3.3. 双向关联...

    Hibernate+中文文档

    6.2.5. 一对多关联(One-to-many Associations) 6.3. 高级集合映射(Advanced collection mappings) 6.3.1. 有序集合(Sorted collections) 6.3.2. 双向关联(Bidirectional associations) 6.3.3. 双向关联...

    Hibernate_Annotation关联映射

    一对多(One-to-Many) 使用@OneToMany批注可定义一对多关联,一对多关联可以是双向关联。 在EJB3规范中多对一这端几乎总是双向关联中的主体(owner)端,而一对多这端关联批注为@OneToMany(mappedBy...) @Entity Public...

    Hibernate_3.2.0_符合Java习惯的关系数据库持久化

    6.2.5. 一对多关联(One-to-many Associations) 6.3. 高级集合映射(Advanced collection mappings) 6.3.1. 有序集合(Sorted collections) 6.3.2. 双向关联(Bidirectional associations) 6.3.3. 双向关联...

    Hibernate中文详细学习文档

    6.2.5. 一对多关联(One-to-many Associations) 6.3. 高级集合映射(Advanced collection mappings) 6.3.1. 有序集合(Sorted collections) 6.3.2. 双向关联(Bidirectional associations) 6.3.3. 双向关联...

    Hibernate 中文 html 帮助文档

    6.2.5. 一对多关联(One-to-many Associations) 6.3. 高级集合映射(Advanced collection mappings) 6.3.1. 有序集合(Sorted collections) 6.3.2. 双向关联(Bidirectional associations) 6.3.3. 双向关联,...

    最全Hibernate 参考文档

    6.2.5. 一对多关联(One-to-many Associations) 6.3. 高级集合映射(Advanced collection mappings) 6.3.1. 有序集合(Sorted collections) 6.3.2. 双向关联(Bidirectional associations) 6.3.3. 三重关联...

    hibernate 体系结构与配置 参考文档(html)

    一对多关联(One-to-many Associations) 6.3. 高级集合映射(Advanced collection mappings) 6.3.1. 有序集合(Sorted collections) 6.3.2. 双向关联(Bidirectional associations) 6.3.3. 双向关联,涉及...

    Hibernate教程

    7.2.5. 一对多关联(One-to-many Associations) 7.3. 高级集合映射(Advanced collection mappings) 7.3.1. 有序集合(Sorted collections) 7.3.2. 双向关联(Bidirectional associations) 7.3.3. 三重关联...

    Hibernate3的帮助文档

    7.2.5. 一对多关联(One-to-many Associations) 7.3. 高级集合映射(Advanced collection mappings) 7.3.1. 有序集合(Sorted collections) 7.3.2. 双向关联(Bidirectional associations) 7.3.3. 三重关联...

    Hibernate中文API大全

    (A mapping like this allows you to map extra columns of a many-to-many association table to the composite element class.) 接下来的的例子是从Order到Item的一个多对多的关联关系, 关联属性是 purchaseDate, ...

    hibernate 框架详解

    一对多关联(One-to-many Associations) 7.3. 高级集合映射(Advanced collection mappings) 7.3.1. 有序集合(Sorted collections) 7.3.2. 双向关联(Bidirectional associations) 7.3.3. 三重关联...

    hibernate3.04中文文档.chm

    22.2. 双向的一对多关系(Bidirectional one-to-many) 22.3. 级联生命周期(Cascading lifecycle) 22.4. 级联与未保存值(Cascades and unsaved-value) 22.5. 结论 23. 示例:Weblog 应用程序 23.1. 持久化类 ...

    Hibernate3+中文参考文档

    6.2.5. 一对多关联(One-to-many Associations) 6.3. 高级集合映射(Advanced collection mappings) 6.3.1. 有序集合(Sorted collections) 6.3.2. 双向关联(Bidirectional associations) 6.3.3. 三重关联...

    NHibernate中文文档

    一对多关联(One-To-Many Associations) 14 延迟初始化(延迟加载)(Lazy Initialization) 14 集合排序(Sorted Collections) 14 使用 &lt;idbag&gt; 14 双向关联(Bidirectional Associations) 14 三重关联(Ternary ...

    Hibernate参考文档

    6.2.5. 一对多关联(One-to-many Associations) 6.3. 高级集合映射(Advanced collection mappings) 6.3.1. 有序集合(Sorted collections) 6.3.2. 双向关联(Bidirectional associations) 6.3.3. 双向关联,...

Global site tag (gtag.js) - Google Analytics