hibernate——一对一、多对一和多对多关系的比较
2014-08-14 10:55
399 查看
几种映射关系,但是有点乱,这里来小结一下。关键是表之间如何产生映射关系,以及产生的表的结构。
1、一对一映射:
一对一是通过one-to-one标签来产生映射关系的,其实,如果单单说是建立两个表之间的关联,只要在一个映射文件中配置one-to-one标签就可以了,在另一个映射文件中,也做类似的配置,只会起到关联的作用,建立起双向的关联。这里举Person和IdCard的例子,IdCard类的映射文件如下:
[html] view
plaincopy
<class name="IdCard" table="id_card">
<id name="id">
<generator class="native"></generator>
</id>
<property name="No"/>
<one-to-one name="person" constrained="true"/>
</class>
constrained="true"指定了将person表的主键设置为id_card表的外键,这样就建立起了两个表的关联,若不指定,两个表就是孤立的,互相没有关系。
建立表的ddl语句如下:
[sql] view
plaincopy
CREATE TABLE `id_card` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`No` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `FK627C1FB4AEED3EC` (`id`),
CONSTRAINT `FK627C1FB4AEED3EC` FOREIGN KEY (`id`) REFERENCES `person` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=gbk
在Person类的映射文件中可以不指定one-to-one标签,但那样建立起来的是单向的映射关系,即从id_card表可以映射到person表,但是反之就不行。这在通过person表查询id_card表时,不能查询。如果要让person关联到id_card那么就要在Person类的映射文件中,也配置一下one-to-one标签了。
onstrained默认值为false
2、多对一映射:
建立两个表的映射的关系,都是通过建立外键来关联的,多对一也不例外,例如员工和部门的关系属于多对一的关系,多个员工属于同一个部门,所以在部门类中要有一个员工的集合属性。要实现双向映射的话,还必须在员工类中有部门的属性。如果单单建立两个表之间的关联,也像一对一一样,只需要在一个映射文件中配置就可以了,但是,多对一的映射文件的配置不像一对一那样简单,相对复杂的是在“一”这个角色,不是只使用一个<one-to-many>就可以了的,看下面这个配置“一”角色的例子:
[html] view
plaincopy
部门类的映射文件:
<class name="Department">
<id name="id">
<generator class="native"/>
</id>
<property name="name"/>
<set name="emps">
<key column="depart_id"/><!-- key指明了员工表中的外键,column为这外键重命名列名-->
<one-to-many class="Employee"/><!-- one-to-many指明了和哪个类进行一对多的映射 -->
</set>
</class>
它是配置了一个set标签,在标签中指定了要关联的类和在要关联类中的外键。“一”这一方是通过这种方式建立和“多”的关联的。那么,要是用“多”那一方怎么建立关联呢?看下例:
[html] view
plaincopy
员工类的映射文件:
<class name="Employee">
<id name="id">
<generator class="native"/>
</id>
<property name="name"/>
<many-to-one name="depart" column="depart_id"></many-to-one>
<!-- many-to-one指明了外键 ,会根据反射机制,找到要和Employee建立多对一关系的类-->
</class>
使用<many-to-one>标签也可以建立起和部门表的关联,而且这种方式要简洁很多。不管用哪种方式建立关联,所得的数据库的结果是一样的,如本例中,建立的员工表的ddl语句为:
[sql] view
plaincopy
CREATE TABLE `employee` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) DEFAULT NULL,
`depart_id` int(11) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `FK4AFD4ACE972E0614` (`depart_id`),
CONSTRAINT `FK4AFD4ACE972E0614` FOREIGN KEY (`depart_id`) REFERENCES `department` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=gbk
3、多对多映射:
因为是多对多的关系,只用两个表是无法表示这种关系的,所以建立出来第三方表,只保存这两个表之间的关系,这样就把多对多映射转换成了两个多对一映射。如果单单是建立两个表之间的关联,和上两种情况一样,只需要在其中一个映射文件中配置即可,但是要建立双向映射的话,就要在两个映射文件中都配置关联了。
这里我们举老师和学生的例子,他们的映射文件分别如下:
[html] view
plaincopy
<class name="Teacher">
<id name="id">
<generator class="native"/>
</id>
<property name="name"/>
<set name="students" table="teacher_student">
<key column="teacher_id"/>
<many-to-many class="Student" column="student_id"/>
</set>
</class>
[html] view
plaincopy
<class name="Student">
<id name="id">
<generator class="native"/>
</id>
<property name="name"/>
<set name="teachers" table="teacher_student">
<key column="student_id"/>
<many-to-many class="Teacher" column="teacher_id"/>
</set>
</class>
是不是看起来和多对一的映射文件有些类似?但是,不同的是,这里出现了第三个表:teacher_student,表中只有两列:teacher_id和student_id,并且分别是teacher和student表的外键,建立的teacher_student表就是老师和学生表之间的关联,其建立的ddl语句为:
[sql] view
plaincopy
CREATE TABLE `teacher_student` (
`teacher_id` int(11) NOT NULL,
`student_id` int(11) NOT NULL,
PRIMARY KEY (`student_id`,`teacher_id`),
KEY `FK2E2EF2DEDE6A927E` (`teacher_id`),
KEY `FK2E2EF2DECDCF47DE` (`student_id`),
CONSTRAINT `FK2E2EF2DECDCF47DE` FOREIGN KEY (`student_id`) REFERENCES `student` (`id`),
CONSTRAINT `FK2E2EF2DEDE6A927E` FOREIGN KEY (`teacher_id`) REFERENCES `teacher` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=gbk
通过上面的总结,应该清楚以下几个问题:
1、如果说单单建立两个表之间的关联,在其中一个映射文件中配置关联就可以了,就能够在数据库中生成外键,建立关联。
2、虽说在一个映射文件中就可以建立两个表的关联,但是不同的映射关系在不同的映射文件中,配置的方法是不同的。
3、若要建立双向的关联的话,就要在两个映射文件中都进行关联配置。
进一步分析‘1 to N’ 和 ‘N to 1’ 之间的关联
hihernate一对多关联映射 , 单向 Employee -----> Department:
多对一关联映射:在'N'的一端加入一个外键指向'1'的一端,它维护的关系是多指向一
一对多关联映射:在'N'的一端加入一个外键指向'1'的一端,它维护的关系是一指向多
也就是说一对多和多对一的映射策略是一样的,只是站的角度不同
hihernate一对多关联映射, 双向 Employee <----->Department:
一对多双向关联映射:
* 在一一端的集合上使用<key>,在对方表中加入一个外键指向'1'端
* 在'N'一端采用<many-to-one>
注意:<key>标签指定的外键字段必须和<many-to-one>指定的外键字段一致,否则引用字段的错误
如果在'1'端维护一对多关联关系,hibernate会发出多余的udpate语句,所以我们一般在'N'的一端来维护关联关系
关于inverse属性:
inverse主要用在一对多和多对多双向关联上,inverse可以被设置到集合标签<set>上,
默认inverse为false,所以我们可以从'1'一端和'N'一端维护关联关系,
如果设置成inverse为true,则我们只能从'N'一端来维护关联关系
inverse和cascade
* inverse是关联关系的控制方向
* cascade操作上的连锁反应
1、一对一映射:
一对一是通过one-to-one标签来产生映射关系的,其实,如果单单说是建立两个表之间的关联,只要在一个映射文件中配置one-to-one标签就可以了,在另一个映射文件中,也做类似的配置,只会起到关联的作用,建立起双向的关联。这里举Person和IdCard的例子,IdCard类的映射文件如下:
[html] view
plaincopy
<class name="IdCard" table="id_card">
<id name="id">
<generator class="native"></generator>
</id>
<property name="No"/>
<one-to-one name="person" constrained="true"/>
</class>
constrained="true"指定了将person表的主键设置为id_card表的外键,这样就建立起了两个表的关联,若不指定,两个表就是孤立的,互相没有关系。
建立表的ddl语句如下:
[sql] view
plaincopy
CREATE TABLE `id_card` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`No` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `FK627C1FB4AEED3EC` (`id`),
CONSTRAINT `FK627C1FB4AEED3EC` FOREIGN KEY (`id`) REFERENCES `person` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=gbk
在Person类的映射文件中可以不指定one-to-one标签,但那样建立起来的是单向的映射关系,即从id_card表可以映射到person表,但是反之就不行。这在通过person表查询id_card表时,不能查询。如果要让person关联到id_card那么就要在Person类的映射文件中,也配置一下one-to-one标签了。
onstrained默认值为false
constrained只能在one-to-one的映射中使用,(一般在主表的映射中,有外键的那个表)。如果constrained=true,则表明存在外键与关联表对应,并且关联表中肯定存在对应的键与其对应, 另外该选项最关键的是影响save和delete的先后顺序。例如增加的时候,如果constainted=true,则会先增加关联表,然后增加本表。删除的时候反之。
[code]one-to-one的单向关联中,如果constrained=false,则会在查询时就全部取出来,用left outer join的方式。如果constrained=true,hibernate即会延迟加载sql,只把主表的查出来,等有用到关联表的再发sql取。
one-to-one的双向关联中,必须设置constrained=true,要不然会有重复数据读,如2个表user,car;在位false时sql如下:select * from user a left outer join car b on a.id=b.id left outer join on user c on a.id=c.id where a.id=? 删除的时候最好删除从表,删除主表会先查询下主表,在联合查询下。
2、多对一映射:
建立两个表的映射的关系,都是通过建立外键来关联的,多对一也不例外,例如员工和部门的关系属于多对一的关系,多个员工属于同一个部门,所以在部门类中要有一个员工的集合属性。要实现双向映射的话,还必须在员工类中有部门的属性。如果单单建立两个表之间的关联,也像一对一一样,只需要在一个映射文件中配置就可以了,但是,多对一的映射文件的配置不像一对一那样简单,相对复杂的是在“一”这个角色,不是只使用一个<one-to-many>就可以了的,看下面这个配置“一”角色的例子:
[html] view
plaincopy
部门类的映射文件:
<class name="Department">
<id name="id">
<generator class="native"/>
</id>
<property name="name"/>
<set name="emps">
<key column="depart_id"/><!-- key指明了员工表中的外键,column为这外键重命名列名-->
<one-to-many class="Employee"/><!-- one-to-many指明了和哪个类进行一对多的映射 -->
</set>
</class>
它是配置了一个set标签,在标签中指定了要关联的类和在要关联类中的外键。“一”这一方是通过这种方式建立和“多”的关联的。那么,要是用“多”那一方怎么建立关联呢?看下例:
[html] view
plaincopy
员工类的映射文件:
<class name="Employee">
<id name="id">
<generator class="native"/>
</id>
<property name="name"/>
<many-to-one name="depart" column="depart_id"></many-to-one>
<!-- many-to-one指明了外键 ,会根据反射机制,找到要和Employee建立多对一关系的类-->
</class>
使用<many-to-one>标签也可以建立起和部门表的关联,而且这种方式要简洁很多。不管用哪种方式建立关联,所得的数据库的结果是一样的,如本例中,建立的员工表的ddl语句为:
[sql] view
plaincopy
CREATE TABLE `employee` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) DEFAULT NULL,
`depart_id` int(11) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `FK4AFD4ACE972E0614` (`depart_id`),
CONSTRAINT `FK4AFD4ACE972E0614` FOREIGN KEY (`depart_id`) REFERENCES `department` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=gbk
3、多对多映射:
因为是多对多的关系,只用两个表是无法表示这种关系的,所以建立出来第三方表,只保存这两个表之间的关系,这样就把多对多映射转换成了两个多对一映射。如果单单是建立两个表之间的关联,和上两种情况一样,只需要在其中一个映射文件中配置即可,但是要建立双向映射的话,就要在两个映射文件中都配置关联了。
这里我们举老师和学生的例子,他们的映射文件分别如下:
[html] view
plaincopy
<class name="Teacher">
<id name="id">
<generator class="native"/>
</id>
<property name="name"/>
<set name="students" table="teacher_student">
<key column="teacher_id"/>
<many-to-many class="Student" column="student_id"/>
</set>
</class>
[html] view
plaincopy
<class name="Student">
<id name="id">
<generator class="native"/>
</id>
<property name="name"/>
<set name="teachers" table="teacher_student">
<key column="student_id"/>
<many-to-many class="Teacher" column="teacher_id"/>
</set>
</class>
是不是看起来和多对一的映射文件有些类似?但是,不同的是,这里出现了第三个表:teacher_student,表中只有两列:teacher_id和student_id,并且分别是teacher和student表的外键,建立的teacher_student表就是老师和学生表之间的关联,其建立的ddl语句为:
[sql] view
plaincopy
CREATE TABLE `teacher_student` (
`teacher_id` int(11) NOT NULL,
`student_id` int(11) NOT NULL,
PRIMARY KEY (`student_id`,`teacher_id`),
KEY `FK2E2EF2DEDE6A927E` (`teacher_id`),
KEY `FK2E2EF2DECDCF47DE` (`student_id`),
CONSTRAINT `FK2E2EF2DECDCF47DE` FOREIGN KEY (`student_id`) REFERENCES `student` (`id`),
CONSTRAINT `FK2E2EF2DEDE6A927E` FOREIGN KEY (`teacher_id`) REFERENCES `teacher` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=gbk
通过上面的总结,应该清楚以下几个问题:
1、如果说单单建立两个表之间的关联,在其中一个映射文件中配置关联就可以了,就能够在数据库中生成外键,建立关联。
2、虽说在一个映射文件中就可以建立两个表的关联,但是不同的映射关系在不同的映射文件中,配置的方法是不同的。
3、若要建立双向的关联的话,就要在两个映射文件中都进行关联配置。
进一步分析‘1 to N’ 和 ‘N to 1’ 之间的关联
hihernate一对多关联映射 , 单向 Employee -----> Department:
多对一关联映射:在'N'的一端加入一个外键指向'1'的一端,它维护的关系是多指向一
一对多关联映射:在'N'的一端加入一个外键指向'1'的一端,它维护的关系是一指向多
也就是说一对多和多对一的映射策略是一样的,只是站的角度不同
hihernate一对多关联映射, 双向 Employee <----->Department:
一对多双向关联映射:
* 在一一端的集合上使用<key>,在对方表中加入一个外键指向'1'端
* 在'N'一端采用<many-to-one>
注意:<key>标签指定的外键字段必须和<many-to-one>指定的外键字段一致,否则引用字段的错误
如果在'1'端维护一对多关联关系,hibernate会发出多余的udpate语句,所以我们一般在'N'的一端来维护关联关系
关于inverse属性:
inverse主要用在一对多和多对多双向关联上,inverse可以被设置到集合标签<set>上,
默认inverse为false,所以我们可以从'1'一端和'N'一端维护关联关系,
如果设置成inverse为true,则我们只能从'N'一端来维护关联关系
inverse和cascade
* inverse是关联关系的控制方向
* cascade操作上的连锁反应
相关文章推荐
- hibernate——一对一、多对一和多对多关系的比较
- hibernate 笔记001---一对多,多对一,多对多,一对一关系汇总
- Hibernate初学中的对多、多对一关系模型及构造函数和构造代码比较
- Hibernate 一对一的关系(one-to-one)
- hibernate主键相同的一对一关系
- Hibernate中的一对多,多对一,多对多,一对一关系
- Hibernate关系映射(2)_一对一双向外键关联
- Hibernate 基于注解的方式 实现的关系映射案例(一对一关系,一对多关系,多对多关系)
- Hibernate 一对多关系映射与一对一关系映射
- 3、Hibernate一对一、一对多、多对多对应关系
- 3、Hibernate一对一、一对多、多对多对应关系
- Hibernate 、多表关联映射 - 一对一关系映射(one- to-one)
- hibernate学习(设计一对一 关系 映射)
- hibernate 一对一主键映射关系
- hibernate级联关系 -----一对一
- Hibernate实体关系映射——单边的一对一关系
- Java程序员从笨鸟到菜鸟之(五十八)细谈Hibernate(九)hibernate一对一关系映射
- 3、Hibernate一对一、一对多、多对多对应关系
- hibernate关系映射 一对一
- Hibernate 、多表关联映射 - 一对一关系映射(one- to-one)