什么是one-to-many?

概念

一对多关联,一个对象通过关联属性能够对应多个对象。
在数据库中表现为:一张表中的记录通过在另一张表中设立外键来与其建立关联关系,外键在另一张表中对应本表中对应记录的主键,且可以拥有相同的外键来对应本表中的同一条记录。

举例:
学生在学校中都有所属的班级,一个班级对象中可以有多个学生对象,而每个学生对象都对应着一个班级。班级和学生之间的关系就是多对一关系。

建立模型

Hibernate:one-to-many(一对多)关联映射详解

使用并配置one-to-many

定义实体类
Student类:

Hibernate:one-to-many(一对多)关联映射详解
Classes类:

Hibernate:one-to-many(一对多)关联映射详解

使用set集合定义关联属性的类型。

PS: Hibernate对set进行了重写,使set支持懒加载,因此Hibernate中一般使用的是set而不是list

略过Student.hbm.xml映射文件,我们主要看Classes.hbm.xml:

Hibernate:one-to-many(一对多)关联映射详解
主键生成策略为native(数据库生成)

使用set标签映射set集合 (没有进行泛型的集合可以存放任何类型的对象),设置set中存放Student类型的对象。
通过key标签指定在one-to-many所指的Student类所对应的表中创建名为classesid字段,该字段作为外键,参照当前类所对应表中的主键。

PS: key标签用来在其他表中设立关联本表的外键字段。

配置原理

将外键字段建立在另一张表中,这个字段参照的是当前表的主键,从而建立两张表的联系。

one-to-many的应用

使用一对多关联进行表的创建和使用

创建表:

Hibernate:one-to-many(一对多)关联映射详解
我们看到t_student表中添加了classid字段,且classid作为外键,参照t_classes表中的主键。

插入数据

运用junit和debug追踪分析代码的执行过程

创建Student对象,并调用save方法:

Hibernate:one-to-many(一对多)关联映射详解

Hibernate访问数据库,从而生成主键,对象进入持久态,这里就不做赘述了,直接将断点下移。

创建出Classes对象,并将Student对象的地址都放入set集合中,然后将set集合的地址放入Classes对象中的students属性中,最后调用save方法:

Hibernate:one-to-many(一对多)关联映射详解

查看对象的状态:

Hibernate:one-to-many(一对多)关联映射详解
可以看到,3个对象都进入持久态,查看执行日志:

Hibernate:one-to-many(一对多)关联映射详解
Hibernate确实是发送了sql语句,但执行Save方法只进行了主键的获取,classid并没有生成。

执行commit操作:

Hibernate:one-to-many(一对多)关联映射详解
Hibernate发送update说明数据发生了改变,生成了classid

我们查看t_student表中的数据:

Hibernate:one-to-many(一对多)关联映射详解
Hibernate:one-to-many(一对多)关联映射详解
我们看到classid中的数据对应着t_classes表中的主键id,形成了一对多关系。

classid的生成:

  1. 执行commit方法,Classes对象从students属性中依次取得student对象的地址;
  2. 通过对象的id找到该对象的类型;
  3. 找到该类型在数据库中对应表中的记录;
  4. 将classes中生成的主键id设到该记录中的classid字段中(通过update更新)

补充说明:
one-to-many没有自动级联,操作不当可能会出现TransientObjectException。

查询数据

使用load加载数据:

Hibernate:one-to-many(一对多)关联映射详解
创建Classes对象,通过id找到表中对应的记录设到Classes对象的属性中

Hibernate根据hbm.xml映射文件给students属性设值:

  1. 通过id找到关联表的外键;
  2. 根据外键找到记录,创建student对象;
  3. 由于该属性通过one-to-many标签配置,于是又在表中依次找到与id相等的外键,并创建出对象;
  4. 自动创建一个set集合,将找到的记录设到set集合中;
  5. 将封装了student对象的set集合自动设到classes对象的属性students中。

查询结果:

Hibernate:one-to-many(一对多)关联映射详解

缺点:

  1. 为了维护关系会发送过多多余的sql语句(update):
    从上述实例我们看出,调用commit方法,Hibernate会为每一条关联的记录发送sql语句,如果关联对象的数量较大,就会因频繁发送sql语句而影响效率。
  2. 如果对classid设置为非空,在key中加上not-null=“true”,将无法正常存储数据:
    classid是通过关联对象的主键生成,如果限定classid为非空,在纳入Session管理时就会抛出异常,导致数据无法存储。

实现one-to-many双向关联

建立模型

Hibernate:one-to-many(一对多)关联映射详解

配置双向关联

在Student实体类中添加classes属性,属性的类型为Classes

Hibernate:one-to-many(一对多)关联映射详解

保持Classes.gbm,xml映射文件不变,在Student.gbm,xml映射文件中添加由many-to-one标签配置的classes属性,该属性在t_Student表中对应的字段名为classid

Hibernate:one-to-many(一对多)关联映射详解
由Student自己建立外键字段classid 参照Classes类对应表中的主键,两张表使用相同的外键,从而实现多对一的双向关联。

注: 建立外键的名字必须和由classes建立的外键名相同

关系的维护

在多对一的单向关联中:
虽然外键字段classid在t_student表中,但classid中的数据是由Classes设置的,因此,Student和Classes之间的关系是通过Classes维护/创建的。

在多对一的双向关联中:
两个对象都能堆关系进行维护/创建

为了解决发送多余的sql语句问题
应尽量使用建立多对一关联关系的对象维护关系。(本例中的Student)因此,我们采用翻转:

Classes.hbm.xml映射文件中,配置student属性的set关键字中加上 inverse=“true” 使classes对象不能维护关系。

Hibernate:one-to-many(一对多)关联映射详解

实例测试:

实例1:

Hibernate:one-to-many(一对多)关联映射详解
创建相关对象

Hibernate:one-to-many(一对多)关联映射详解
两个Student对象中的classes属性都为null,student对象没有设置关联属性,此时对象处于能够维护关系但不维护关系的状态。

对classes对象调用save方法

Hibernate:one-to-many(一对多)关联映射详解
Classes对象中的students属性中存储了Student对象的地址,但由于我们配置了classes对象不能维护关系,且Student对象中关联属性为空,也不维护关系。

执行commit,查看表中存储的结果:

Hibernate:one-to-many(一对多)关联映射详解
数据库中外键classid的值为null,记录之间没有建立关系。

实例2:

Hibernate:one-to-many(一对多)关联映射详解

既然不让Classes维护关系,那么索性就由Student来维护关系

Hibernate:one-to-many(一对多)关联映射详解
Student对象的关联属性classes中存放了关联对象classes的地址

执行commit,查看数据库存储结果:

Hibernate:one-to-many(一对多)关联映射详解
小结:
通过此方法存储数据的过程实质上就是==many-to-one(多对一)==关系的存储过程。

实例3:

Hibernate:one-to-many(一对多)关联映射详解
查看对象的状态

Hibernate:one-to-many(一对多)关联映射详解
Student对象的classes属性都存储了Classes对象的地址

对classes对象调用save方法:

Hibernate:one-to-many(一对多)关联映射详解
自动生成id

Hibernate:one-to-many(一对多)关联映射详解
Hibernate发送sql语句

Hibernate:one-to-many(一对多)关联映射详解
我们看到,生成了classid

classid的生成过程:

Classes对象通过students属性找到Student对象后,由于不能维护关系,因此要由Student对象来维护,通过级联,使Student对象进入持久态,自动生成id,将classes属性所指Classes对象的的id设到外键字段classid上。
这样就由Student建立了两张表之间的关系

说明:本文仅用作学习笔记,无其他用途,如有冒犯可联系本人删除

相关文章:

  • 2021-12-24
  • 2021-07-10
  • 2021-11-23
  • 2022-01-28
  • 2022-01-07
  • 2021-10-05
  • 2021-04-20
  • 2022-12-23
猜你喜欢
  • 2021-04-16
  • 2021-11-11
  • 2022-01-14
  • 2021-11-10
  • 2022-12-23
  • 2021-12-09
  • 2021-12-27
相关资源
相似解决方案