`

一对多单向和双向映射

阅读更多

一、一对多单向关联

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

Hibernate一对多单向关联映射

这种映射的本质是利用了多对一的关联映射的原理

多对一关联映射:是在多的一端添加一个外键维护多指向一的关联引用
一对多关联映射:是在多的一端添加一个外键维护一指向多的关联引用

也就是说,一对多和多对一的映射策略是一致的,只是站的角度不同

缺点:
  * 更新student表中的classesid字段时,需要对每一个student发出一个update的sql,
    来更新classesid字段
  * 如果将t_student表中的classesis设置为非空,则不能保存student数据,因为关系是由
    classes维护的,在保存student时,还没有对应的classesid被生成 	

 

 

具体示例如下:

package com.lwf.hibernate.pojo;

import java.util.HashSet;
import java.util.Set;

public class Classes {

	private int id;
	private String name;
	private Set students = new HashSet();
	
	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;
	}
	public Set getStudents() {
		return students;
	}
	public void setStudents(Set students) {
		this.students = students;
	}
	
}

 

package com.lwf.hibernate.pojo;

public class Student {

	private int id;
	private String name;
	private int age;

	
	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;
	}
	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}
	
}

 

Classes.hbm.xml

<?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.lwf.hibernate.pojo">
	
		<class name="Classes" table="t_classes">
			<id name="id">
				<generator class="native"/>
			</id>
			<property name="name"/>
			<set name="students" >
				<key column="class_id" ></key>
				<one-to-many class="Student" />
			</set>
			
		</class>
	</hibernate-mapping>

 Student.hbm.xml

<?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.lwf.hibernate.pojo">
		<class name="Student" table="t_student">
			<id name="id">
				<generator class="native"/>
			</id>
			<property name="name"/>
			<property name="age"/>
			
		</class>
		
	</hibernate-mapping>

  

具体的数据库结构:

 

mysql> desc student;
+----------+--------------+------+-----+---------+----------------+
| Field    | Type         | Null | Key | Default | Extra          |
+----------+--------------+------+-----+---------+----------------+
| id       | int(11)      | NO   | PRI | NULL    | auto_increment |
| name     | varchar(255) | YES  |     | NULL    |                |
| class_id | int(11)      | YES  | MUL | NULL    |                |
+----------+--------------+------+-----+---------+----------------+
3 rows in set (0.06 sec)

mysql> desc t_class;
+-------+--------------+------+-----+---------+----------------+
| Field | Type         | Null | Key | Default | Extra          |
+-------+--------------+------+-----+---------+----------------+
| id    | int(11)      | NO   | PRI | NULL    | auto_increment |
| name  | varchar(255) | YES  |     | NULL    |                |
+-------+--------------+------+-----+---------+----------------+

 

 测试方法:

package com.lwf.hibernate.test;

import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;

import junit.framework.TestCase;

import org.hibernate.Session;

import com.lwf.hibernate.pojo.Classes;
import com.lwf.hibernate.pojo.Student;
import com.lwf.hibernate.util.HibernateUtil;

public class One2Many_Test extends TestCase{

	//从classes这一端来维护,即在单方维护,会产生insert和update语句.
	public void testClasses(){
		Session session = HibernateUtil.getSession();
		session.beginTransaction();
		try{
			
			Set students = new HashSet();
			for(int i=0;i<5;i++){
				Student s = new Student();
				s.setName("name" + i);
				s.setAge((10 + i));
				students.add(s);
				session.save(s);
			}
			
			
			Classes cla = new Classes();
			cla.setName("class1");
			cla.setStudents(students);
			session.save(cla);
			//先保存,最后根据class_id更新Student
			
			HibernateUtil.commit(session);
		}catch(Exception e){
			HibernateUtil.roolback(session);
		}finally{
			HibernateUtil.closeSession(session);
		}
	}
	
	
	public void testLoad(){
		Session session = HibernateUtil.getSession();
		session.beginTransaction();
		try{
			Classes s = (Classes)session.load(Classes.class, 1);
			Set student = s.getStudents();
			for (Iterator iterator = student.iterator(); iterator.hasNext();) {
				Student stu = (Student) iterator.next();
				System.out.println(stu.getName());
			}
			HibernateUtil.commit(session);
		}catch(Exception e){
			HibernateUtil.roolback(session);
		}finally{
			HibernateUtil.closeSession(session);
		}
	}
	
	
}

 

 

注意保存生成的语句:

Hibernate: insert into t_student (name, age) values (?, ?)
Hibernate: insert into t_student (name, age) values (?, ?)
Hibernate: insert into t_student (name, age) values (?, ?)
Hibernate: insert into t_student (name, age) values (?, ?)
Hibernate: insert into t_student (name, age) values (?, ?)
Hibernate: insert into t_classes (name) values (?)
Hibernate: update t_student set class_id=? where id=?
Hibernate: update t_student set class_id=? where id=?
Hibernate: update t_student set class_id=? where id=?
Hibernate: update t_student set class_id=? where id=?
Hibernate: update t_student set class_id=? where id=?

 

先保存student,再保存classes最后根据classes的id更新student的class_id

这实际上是由classes这方来维护两者的关联关系.

正常情况下关系应该由多的一方来维护,在双向关联中我们从多方来维护两者的关系.这样就可以避免update语句的出现.而是直接insert即可.

 

二、一对多双向关联

 

下面我们看看双向的一对多映射,实际上就是把一对多与多对一结合起来看.

Hibernate 一对多双向关联映射

一对多双向关联映射的方法:

在一一端:
在集合标签里面使用<key>标签来表明需要在对方的表中添加一个外键指向一一端。

在多一端:
使用<many-to-one>标签来映射。

需要注意:<key>标签所指定的外键字段名需要与<many-to-one>标签定义的外键字段名一致,否则便会造成引用数据的
丢失!

--------------------------------------------------------------------------------------
如果从一端来维护一对多双向关联的关系,hibernate会发出多余的update语句,所以
一般地情况下,我们便会从多一端来维护其关联关系!
----------------------------------------------------

  

 

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

package com.lwf.hibernate.pojo;

public class Student {

	private int id;
	private String name;
	private int age;
	private Classes classes;
	
	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;
	}
	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}
	public Classes getClasses() {
		return classes;
	}
	public void setClasses(Classes classes) {
		this.classes = classes;
	}
	
}

 

Student.hbm.xml

<?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.lwf.hibernate.pojo">
		<class name="Student" table="t_student">
			<id name="id">
				<generator class="native"/>
			</id>
			<property name="name"/>
			<property name="age"/>
			<many-to-one name="classes" column="class_id"></many-to-one>
		</class>
		
	</hibernate-mapping>

 

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

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

package com.lwf.hibernate.test;

import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;

import junit.framework.TestCase;

import org.hibernate.Session;

import com.lwf.hibernate.pojo.Classes;
import com.lwf.hibernate.pojo.Student;
import com.lwf.hibernate.util.HibernateUtil;

public class One2Many_Test extends TestCase{

	//从classes这一端来维护,即在单方维护,会产生insert和update语句.
	public void testClasses(){
		Session session = HibernateUtil.getSession();
		session.beginTransaction();
		try{
			
			Set students = new HashSet();
			for(int i=0;i<5;i++){
				Student s = new Student();
				s.setName("name" + i);
				s.setAge((10 + i));
				students.add(s);
				session.save(s);
			}
			
			
			Classes cla = new Classes();
			cla.setName("class1");
			cla.setStudents(students);
			session.save(cla);
			//先保存,最后根据class_id更新Student
			
			HibernateUtil.commit(session);
		}catch(Exception e){
			HibernateUtil.roolback(session);
		}finally{
			HibernateUtil.closeSession(session);
		}
	}
	
	
	//由于配置了双向关联,所以下面先保存了classes再保存student只有insert语句,没有update语句
	public void testStudent(){
		Session session = HibernateUtil.getSession();
		session.beginTransaction();
		try{
			Classes cla = new Classes();
			cla.setName("class111");
			session.save(cla);
			for (int i = 0; i < 5; i++) {
				Student s  = new Student();
				s.setName("name111"+i);
				s.setClasses(cla);
				session.save(s);
			}
			HibernateUtil.commit(session);
		}catch(Exception e){
			HibernateUtil.roolback(session);
		}finally{
			HibernateUtil.closeSession(session);
		}
			
	}
	
	//从classes得到student,主要测试单向关联
	public void testLoadClass(){
		Session session = HibernateUtil.getSession();
		session.beginTransaction();
		try{
			Classes s = (Classes)session.load(Classes.class, 1);
			Set student = s.getStudents();
			for (Iterator iterator = student.iterator(); iterator.hasNext();) {
				Student stu = (Student) iterator.next();
				System.out.println(stu.getName());
			}
			HibernateUtil.commit(session);
		}catch(Exception e){
			HibernateUtil.roolback(session);
		}finally{
			HibernateUtil.closeSession(session);
		}
	}
	
	//从student得到classes,配置了双向关联后的测试
	public void testLoadStudent(){
		Session session = HibernateUtil.getSession();
		session.beginTransaction();
		try{
			Student s = (Student)session.load(Student.class, 1);
			System.out.println(s.getName());
			System.out.println(s.getClasses().getName());
			HibernateUtil.commit(session);
		}catch(Exception e){
			HibernateUtil.roolback(session);
		}finally{
			HibernateUtil.closeSession(session);
		}
	}
	
	
}

主要区别:

由于配置了双向关联,所以下面先保存了classes再保存student只有insert语句,没有update语句

以下是testStudent方法产生的SQL语句

Hibernate: insert into t_classes (name) values (?)
Hibernate: insert into t_student (name, age, class_id) values (?, ?, ?)
Hibernate: insert into t_student (name, age, class_id) values (?, ?, ?)
Hibernate: insert into t_student (name, age, class_id) values (?, ?, ?)
Hibernate: insert into t_student (name, age, class_id) values (?, ?, ?)
Hibernate: insert into t_student (name, age, class_id) values (?, ?, ?)

 

 

 

三、下面讨论一下关于INVERSE的用法:

关于inverse属性:
inverse属性可以被设置到集合标签<set>上,表示在存储双向一对多关联映射的时候,
存储的是那一方的关联引用。默认情况下,inverse=“false”,所以,我们可以从一一端
或者多一端来维护两者之间的关系;如果我们设置inverse=“true”,则只能通过多一端来
维护两者之间的关系。inverse属性可以被用在一对多和多对多双向关联中;

注意:inverse属性只是在将数据持久化到数据库的过程中发挥作用.

 

主要看看上面双向关联中testClasses方法,当classes.hbm.xml文件如下时

<?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.lwf.hibernate.pojo">
	
		<class name="Classes" table="t_classes">
			<id name="id">
				<generator class="native"/>
			</id>
			<property name="name"/>
			<set name="students" >
				<key column="class_id" ></key>
				<one-to-many class="Student" />
			</set>
			
		</class>
	</hibernate-mapping>

 我们知道上面的testClasses方法产生的sql语句是先insert再update,上面已经讲到是从一方来维护关联关系的.那么现在我们把classes.hbm.xml的set上面增加inverse="true"即

<set name="students" inverse="true">
	<key column="class_id" ></key>
	<one-to-many class="Student" />
</set>
			

 那么这时候testClasses方法产生的SQL语句是?

Hibernate: insert into t_student (name, age, class_id) values (?, ?, ?)
Hibernate: insert into t_student (name, age, class_id) values (?, ?, ?)
Hibernate: insert into t_student (name, age, class_id) values (?, ?, ?)
Hibernate: insert into t_student (name, age, class_id) values (?, ?, ?)
Hibernate: insert into t_student (name, age, class_id) values (?, ?, ?)
Hibernate: insert into t_classes (name) values (?)

 

虽然只产生了insert语句,但因为t_classes插入语句在后,所以数据库里面对应的t_student的记录:

mysql> select * from t_student;
+----+-------+------+----------+
| id | name  | age  | class_id |
+----+-------+------+----------+
|  1 | name0 |   10 |     NULL |
|  2 | name1 |   11 |     NULL |
|  3 | name2 |   12 |     NULL |
|  4 | name3 |   13 |     NULL |
|  5 | name4 |   14 |     NULL |
+----+-------+------+----------+

 显然class_id为空.没有更新.

即用了INVERSE,将强制要求从多的一方来维护关系.即当设置了INVERSE属性后,要求使用testStudent方法来做保存.

而INVERSE属性没有设置时,对于双向的一对多关联,我们即可以使用testClasses又可以使用testStudent方法进行保存,但是他们的区别是testClasses操作中有insert和update语句,而testStudent只有insert语句.显然使用testStudent即从多方来维护关联关系节约了资源...

分享到:
评论

相关推荐

    hibernate单向多对多映射(XML版)

    不过,如果需要双向映射,`Course`也需要定义一个`&lt;set&gt;`元素,与`Student`的映射相对应。 通过这样的配置,Hibernate就能理解`Student`和`Course`之间的多对多关系,并在操作时自动处理关联表的插入、更新和删除。...

    Hibernate双向一对一关联映射(注解版)

    在Hibernate中,一对一关联映射分为单向和双向。单向一对一映射通常涉及一个实体持有另一个实体的引用,而双向一对一映射则意味着两个实体都可以互相引用。这种关联关系在数据库层面通常通过主键外键约束来实现,但...

    Java的Hibernate框架中一对多的单向和双向关联映射

    首先,我们来看**一对多单向关联映射**。在这个关系中,一方(如班级)知道另一方(如学生),但另一方并不知道这一方。在对象模型中,这通常表现为一个类(如Classes)有一个集合属性(如Set),用来存储多个相关联...

    Hibernate一对多单向关联映射

    通过以上内容,我们对Hibernate中的一对多单向关联映射有了全面的理解,包括其配置方式、代码实现、使用技巧以及需要注意的细节。在实际项目开发中,正确理解和运用这些知识能够有效地提升数据操作的效率和代码的可...

    hibernate one-to-one 一对一唯一外键关联映射_单向 and 双向

    在本文中,我们将详细介绍Hibernate一对一唯一外键关联映射的概念、配置方法和实践应用。 一对一唯一外键关联映射的概念 在Hibernate中,一对一唯一外键关联映射是指两个实体之间的关联关系,其中一个实体作为外键...

    hibernate关联映射详解

    包含《多对多双向关联映射》《多对一单向关联映射》《多对一双向关联映射》《一对多单向关联映射》等文档,并有图解及例子,非常适合新手学习,尤其是刚刚接触hibernate,对映射关系不清楚的。。。。

    hibernate一对多,多对一,一对多双向关联

    在数据库设计中,这种关联关系是常见的,例如一个用户可以有多个订单(一对多),一个订单对应一个用户(多对一),而一个商品可以被多个订单购买,同时一个订单也可以包含多个商品(一对多双向关联)。这个标题暗示...

    Hibernate一对一唯一外键关联映射(单向关联)

    在本教程中,我们将探讨如何实现一对一唯一外键关联映射,特别关注单向关联的情况。 ### 1. Hibernate一对一关联概述 一对一关联分为两种类型:共享主键关联(Primary Key Join)和唯一外键关联(Unique Foreign ...

    hibernate03:多对一单向关联、多对一双向关联

    本文主要探讨的是Hibernate中的两种关联关系:多对一单向关联和多对一双向关联。通过理解这两种关联方式,我们可以更好地设计和实现复杂的数据库模型。 首先,我们来看**多对一单向关联**。这种关联意味着一个实体...

    hibernate one-to-many 单/双向关联映射配置心得

    本文主要关注Hibernate中的一个核心概念——一对一(One-to-One)、一对多(One-to-Many)和多对一(Many-to-One)关联映射,特别是关于“一到多”单向和双向关联映射的配置心得。 首先,让我们了解“一到多”关联...

    hibernate一对多双向

    在探讨“Hibernate一对多双向”这一主题时,我们首先需要...总之,“Hibernate一对多双向”关联在企业级应用中非常常见,通过深入理解其配置和实现原理,开发者可以更好地设计和优化数据库模型,以满足复杂业务需求。

    hibernate一对多关联映射

    总结,Hibernate的一对多关联映射提供了处理实体间多对一关系的能力,既可实现单向关联,也可实现双向关联。通过合理配置,可以优化数据加载策略,进行级联操作,并方便地进行数据的保存和查询。在实际开发中,理解...

    hibernate一对多关联映射学习小结

    在Hibernate中,一对多关联映射和多对一关联映射的区别在于维护的关系不同。多对一关联映射中,多的一端维护一的一端的关系,在加载多的一端时,可以将一的一端加载上来。一对多关联映射中,一的一端维护多的一端的...

    hibernate多对多关联映射(单项关联)

    总的来说,这篇博客和相关代码示例为开发者提供了一个理解和实现Hibernate中多对多单向关联的起点,帮助他们更好地处理复杂的数据库关系映射。学习和实践这部分内容对于提升Java后端开发能力,特别是使用Hibernate...

Global site tag (gtag.js) - Google Analytics