• 欢迎来到本博客,希望可以y一起学习与分享

Hibernate(三)

Java benz 4年前 (2018-02-20) 123次浏览 0个评论 扫描二维码
文章目录[隐藏]

一、表关系的分析

Hibernate框架实现了ORM的思想,将关系数据库中表的数据映射成对象,使开发人员把对数据库的操作转化为对对象的操作,Hibernate的关联关系映射主要包括多表的映射配置、数据的增加、删除等。
数据库中多表之间存在着三种关系,也就是系统设计中的三种实体关系。如图所示。

从图可以看出,系统设计的三种实体关系分别为:多对多、一对多和一对一关系。在数据库中实体表之间的关系映射是采用外键来描述的,具体如下。

表与表的三种关系

【一对多】
建表原则:在多的一方创建外键指向一的一方的主键:

【多对多】
建表原则:创建一个中间表,中间表中至少两个字段作为外键分别指向多对多双方的主键

【一对多】
建表原则有两种:
一种:唯一外键对应:假设一对一中的任意一方为多,在多的一方创建外键指向一的一方的主键,然后将外键设置为唯一。
二种:主键对应:一方的主键作为另一方的主键。

数据库表能够描述的实体数据之间的关系,通过对象也可以进行描述,所谓的关联映射就是将关联关系映射到数据库里,在对象模型中就是一个或多个引用。在Hibernate中采用Java对象关系来描述数据表之间的关系,具体如图所示。

从图可以看出,通过一对一的关系就是在本类中定义对方类型的对象,如A中定义B类类型的属性b, B类中定义A类类型的属性a;一对多的关系,图中描述的是一个A对应多个B类类型的情况,需要在A类以Set集合的方式引入B类型的对象,在B类中定义A类类型的属性a;多对多的关系,在A类中定义B类类型的Set集合,在B类中定义A类类型的Set集合,这里用Set集合的目的是避免了数据的重复。
以上就是系统模型中实体设计的三种关联关系,由于一对一的关联关系在开发中不常使用,所以我们不单独讲解,了解即可。那么接下来我们就先来学习一下一对多的关系映射吧。

Hibernate的一对多关联映射

创建表

创建联系人表:cst_linkman

联系人表中存在外键(lkm_cust_id 即所属客户id),外键指向客户表:

创建实体

【客户的实体】:

【联系人的实体】

创建映射:

【客户的映射】

使用set集合来描述Customer. java类中的属性linkMans。在Hibernate的映射文件中,使用标签用来描述被映射类中的Set集合,标签的column属性值对应文件多的一方的外键名称,在Customer. java客户类中,客户与联系人是一对多的关系,Hibernate的映射文件中,使用标签来描述持久化类的一对多关联,其中class属性用来描述映射的关联类。
【联系人映射】

标签定义两个持久化类的关联,这种关联是数据表间的多对一关联,联系人与客户就是多对一的关系,所以用标签来描述。标签的name属性用来描述customer在LinkMan.java类中的属性的名称,class属性用来指定映射的类,column属性值对应表中的外键列名。

将映射添加到配置文件

hibernate.cfg.xml

编写测试代码:

在配置文件中添加了自动建表信息后,运行程序时,程序会自动创建两张表,并且插入数据。使用Junit4 运行 testOneToMany()方法后,控制台输出结果,如图所示

从图的输出结果可以看到,拉制台成功输出了三条insert语句和两条update语句,此时查询数据库中两张表及表中的数据后,查询结果如图所示。

从上图的查询结果可以看出,数据表创建成功,并成功插入了相应数据。那么一个基本的一对多的关联关系映射就己经配置好了。以上我们的代码可以发现我们建立的关系是双向的,即客户关联了联系人,同时联系人也关联了客户。

这就是双向关联,那么既然己经进行了双向的关联关系的设置,那么我们还保存了双方,那如果我们只保存一方是否可以呢?也就是说我们建立了双向的维护关系,只保存客户或者只保存联系人是否可以。那么我们来进行一下测试。

我们执行这段代码,会出现如下错误:


这样操作显然不行,无论从那一方保存都会出现同样的异常:瞬时对象异常。一个持久态对象关联了一个瞬时态对象,那就说明我们不能只保存一方。那如果我们就想只保存一个方向应该如何进行操作呢,那么我们可以使用Hibernate的级联操作,那么我们来看下Hibernate的级联吧。

三、一对多的相关操作

级联操作是指当主控方执行保存、更新或者删除操作时,其关联对象(被护方)也执行相同的操作。在映射文件中通过对cascade属性的设置来控制是否对关联对象采用级联操作,级联操作对各种关联关系都是有效的。

级联保存或更新

级联是有方向性的,所谓的方向性指的是,在保存一的一方级联多的一方和在保存多的一方级联一的一方。
【保存客户级联联系人】
首先要确定我们要保存的主控方是那一方,我们要保存客户,所以客户是主控方,那么需要在客户的映射文件中进行如下的配置。

然后我们就可以编写测试代码了,代码如下:

【保存联系人后级联客户】
同样我们需要确定主控方,现在我们的主控方是联系人。所以需要在联系人的映射文件中进行配置,内容如下

然后我们就可以编写代码进行测试了。测试代码如下

到这我们己经可以看到级联保存或更新的效果了。那么我们维护的时候都是双向的关系维护。那么这种关系到底表述的是什么含义呢?我们可以通过下面的测试来更进一步了解关系的维护(对象导航)的含义。

测试对象的导航的问题

我们所说的对象导航其实就是在维护双方的关系。

这种关系有什么用途呢?我们可以通过下面的测试来更进一步学习Hibernate。
我们在客户和联系人端都配置了cascade=”save-update”,然后进行如下的关系设置。会产生什么样的效果呢?

我们执行第24行的时候,问会执行几条insert语句呢?其实发现会有4条snsert语句的,因为联系人1关联了客户,客户又关联了联系人2和联系人3,所以当保存联系人1的时候,联系人1是可以进入到数据库的,它关联的客户也是会进入到数据库的(因为联系人一端配置了级联),那么客户进入到数据库以后,联系人2和联系人3也同样会进入到数据库(因为客户一端配置了级联),所以会有4条insert语句。
我们执行25行的时候,问会有几条insert语句?这时我们保存的客户对象,可以对象关联了联系人2和联系人3,那么客户在保存进入数据库的时候,联系人2和联系人3也会进入到数据库,所以是3条insert语句。
同理我们执行26行代码的时候,只会执行1条insert语句,因为联系人2会保存到数据库,但是联系人2没有客户客户建立关系。所以客户不会保存到数据库。
到这我们应该更加理解了Hibernate的这种关系的建立和级联的关系了。那么级联还有那些操作呢?接下来我们来学习级联删除的操作。

Hibernate的级联删除

我们之前学习过级联保存或更新,那么再来看级联删除也就不难理解了,级联删除也是有方向性的,删除客户同时级联删除联系人,也可以删除联系人同时级联删除客户(这种需求很少)。
如果是删除客户并删除关联的联系人,那么先在客户配置文件

必须写 inverse=”true” cascade=”delete” 否则,关联联系人有数据的话,是删除不了的 。

如果,删除关联的联系人数据,顺便把客户也删除,那么先到联系人配置文件配置一下

必须写 cascade=”delete” ,否则只删除联系人数据,客户数据不会自动删除

双向关联产生多余的SQL语句

到这我们己经了解了Hibernate级联的基本配置和使用。但是有些时候我们需要进行如下的操作数据库中记录如下
客户表

联系人表

需要将2号联系人关联给2号客户。也就是将2号李秘书这个联系人关联给2号刘总这个客户。
编写修改2号客户关联的联系人的代码。

运行该代码,控制台会输出内容, 我们会发现执行了两次update语句,其实这两个update都是修改了外键的操作,那么为什么发送两次呢?那么我们来分析一下产生这种问题的原因:

我们己经分析过了,因为双向维护了关系,而且持久态对象可以自动更新数据库,更新客户的时候会修改一次外键,更新联系人的时候同样也会修改一次外键。这样就会产生了多余的SQL那么问题产生了,我们又该如何解决呢?
其实解决的办法很简单,只需要将一方放弃外键维护权即可。也就是说关系不是双方维护的,只需要交给某一方去维护就可以了。通常我们都是交给多的一方去维护的。为什么呢?因为多的一方才是维护关系的最好的地方,举个例子,一个老师对应多个学生,一个学生对应一个老师,这是典型的一对多。那么一个老师如果要记住所有学生的名字很难的,但如果让每个学生记住老帅的名
字应该不难。其实就是这个道理。所以在一对多中,一的一方都会放弃外键的维护权〔关系的维护)。
这个时候如果想让一的一方放弃外键的维护权,只需要进行如下的配置即可。

inverse的默认值是false,代表不放弃外键维护权,配置值为true,代表放弃了外键的维护权。
这个时候再来执行之前的操作,这个时候我们会发现就不会出现上述的问题了,不会产生多余的SQL了(因为一的一方已经放弃了外键的维护权)。
那么这个问题我们己经解决了,但是有很多同学对应cascade和inverse还是不是太懂,我们可以通过下面的案例区分cascade和
inverse的区别,因为这两个参数我们以后的开发中会经常使用。

区分cascade和inverse

这个时候我们会发现,如果在set集合上配置cascade=”save-update” inverse=”true 了,那么执行保存客户的操作,会发现客户和联系人都进入到数据库了,但是没有外键,是因为配置了cascade所以客户关联的联系人会进入到数据库,但是客户一端放弃了外键维护权,所以联系人插入到数据库以后是没有外键的。
一对多己经完成了,那么我们来看下Hibernate中的多对多的关系的配置。

Hibernate的多对多关联关系映射

创建表:

创建sys_user,sys_role,sys_user_role三张表。
数据模型如下:

创建实体

【用户实体】

【角色实体】

创建映射

【用户的映射:】

【角色的映射:】

在核心配置中加入映射文件

编写测试类

在多对多的保存操作中,如果进行了双向维护关系,就必须有一方放弃外键维护权。一般由被动方放弃,用户主动选择角色,角色是被选择的,所以一般角色要回放弃外键维护权。但如果只进行单向维护关系,那么就不需要放弃外键维护权了。
将数据保存到数据库了以后,那么多对多会有哪些相关的操作呢?我们来学习一下多对多的相关的操作。

多对多的相关操作

级联保存或更新

之前己经学习过一对多的级联保存了,那么多对多也是一样的。如果只保存单独的一方是不可以的,还是需要保存双方的。如果就想保存一方就需要设置级联操作了。同样要看保存的主控方是哪一端,就需要在那一端进行配置。
【保存用户级联角色】
保存的主控方是用户,需要在用户一端配置:

配置好了级联了以后,就可以编写测试代码了。

【保存角色级联用户】
保存的主控方是角色,就需要在角色端配置

配置好了级联了以后,就可以编写测试代码了。

级联保存说完了,那么我们来看下级联删除的操作,但是在多对多种级联删除是不会使用的,因为我们不会有这类的需求,比如删除用户,将用户关联的角色一起删除,或者删除角色的时候将用户删除掉。这是不合理的。但是级联删除的功能Hibernate已经提供了该功能。所以我们只需要了解即可。

级联删除:(了解)

【删除用户级联角色】
主控方是用户,所以需要在用户端配置


配置好了以后就可以编写代码了。

这个时候我们发现用户被删除了,同时用户所关联的角色也一起被删除了。
【册l除角色级联删除用户】
主控方是角色,所以需要在角色端配置

配置好了以后就可以编写代码了。

这个时候我们发现角色被删除了,同时角色所关联的用户也一起被删除了。
多对多的级联我们己经介绍过了,但是级联并不是主要的操作,我们其实更多的会去使用多对多的一些其他的操作,比如给某个用户选择一个新的角色,或者为某个用户改选己经选好的新角色,或者为某个用户移除某个角色。这些操作是我们以后开发中经常使用的。所以我们来学习下如何完成类似的相关的操作。

多对多的其他操作:

其实多对多的关系主要是靠中间表来维护的,那么在Hibernate中多对多主要是靠关联的集合来维护的,所以我们只需要关心如何操作性集合即可。那么我们来看下面的几个示例
【删除某个用户的角色】

【将某个用户的角色改选】

【给某个用户添加新角色】

以上的这些操作是我们以后在多对多的关系中经常使用的操作,所以需要大家记住。


文章 Hibernate(三) 转载需要注明出处
喜欢 (0)

您必须 登录 才能发表评论!