Hibernate 映射关联关系.docx

上传人:b****2 文档编号:2621329 上传时间:2023-05-04 格式:DOCX 页数:21 大小:21.36KB
下载 相关 举报
Hibernate 映射关联关系.docx_第1页
第1页 / 共21页
Hibernate 映射关联关系.docx_第2页
第2页 / 共21页
Hibernate 映射关联关系.docx_第3页
第3页 / 共21页
Hibernate 映射关联关系.docx_第4页
第4页 / 共21页
Hibernate 映射关联关系.docx_第5页
第5页 / 共21页
Hibernate 映射关联关系.docx_第6页
第6页 / 共21页
Hibernate 映射关联关系.docx_第7页
第7页 / 共21页
Hibernate 映射关联关系.docx_第8页
第8页 / 共21页
Hibernate 映射关联关系.docx_第9页
第9页 / 共21页
Hibernate 映射关联关系.docx_第10页
第10页 / 共21页
Hibernate 映射关联关系.docx_第11页
第11页 / 共21页
Hibernate 映射关联关系.docx_第12页
第12页 / 共21页
Hibernate 映射关联关系.docx_第13页
第13页 / 共21页
Hibernate 映射关联关系.docx_第14页
第14页 / 共21页
Hibernate 映射关联关系.docx_第15页
第15页 / 共21页
Hibernate 映射关联关系.docx_第16页
第16页 / 共21页
Hibernate 映射关联关系.docx_第17页
第17页 / 共21页
Hibernate 映射关联关系.docx_第18页
第18页 / 共21页
Hibernate 映射关联关系.docx_第19页
第19页 / 共21页
Hibernate 映射关联关系.docx_第20页
第20页 / 共21页
亲,该文档总共21页,到这儿已超出免费预览范围,如果喜欢就下载吧!
下载资源
资源描述

Hibernate 映射关联关系.docx

《Hibernate 映射关联关系.docx》由会员分享,可在线阅读,更多相关《Hibernate 映射关联关系.docx(21页珍藏版)》请在冰点文库上搜索。

Hibernate 映射关联关系.docx

Hibernate映射关联关系

Hibernate映射关联关系

一、映射多对一关联关系。

1.单向的多对一

(1)以Customer和Order为例:

一个用户可以发出多个订单,而一个订单只能属于一个客户。

从Order到Customer是多对一关联关系。

(2)创建Customer和Order表。

Create

(3)用IntellijIdea自动生成关联关系,以及对应的Entitiy.hbm.xml和持久化类。

 

说明:

其中Type是用来修饰对应的AttributeName的。

在Order端,定义Customer类,一个订单属于一个客户。

而在Customer端,一个客户可以有多个订单,因为是单向的,所以这里放弃属性的添加。

在JoinColumns定义了Order和Customer之间的关联关系,order表中的customer_id外键和customer表中的customer_id主键关联。

来看生成的Schema:

 

没有勾选customer_id,是因为IntellijIdea没法直接映射为Customer类型的customer。

Order.hbm.xml

使用节点来维护多对一关联关系。

name属性:

多这一端关联的一那一端的属性的名称。

class属性:

关联的一端的属性的类型。

column属性:

一那一端在多的一端对应的数据表中的外键。

可以任意命名,但需要和数据表中的字段对应。

(4)单向多对一的CRUD以及需要注意的问题。

<1>新增

①先保存一的一端Customer,后保存多的一端Order。

Save.java

打印SQL:

Output

结论:

发送了3条INSERT语句。

②先保存多的一端Order,再保存一的一端Customer。

Save2.java

打印SQL:

Output2

结论:

发送了3条INSERT语句,2条UPDATE语句。

总结:

在单向多对一的关联关系下,先插入1的一端会减少SQL语句的执行,性能更高。

<2>删除

先删除1的一端。

Delete.java

控制台打印:

Cannotdeleteorupdateaparentrow:

aforeignkeyconstraintfails(`hibernate`.`order`,CONSTRAINT`FK_m6q2ofkj1g5aobtb2p00ajpqg`FOREIGNKEY(`customer_id`)REFERENCES`customer`(`customer_id`))

结论:

在不设置级联关系的前提下,不能删除1的一端。

<3>更新

Update.java

Output

<4>查询

①查询n的一端,但是不使用查询出来关联的1的一端的对象。

@Test

publicvoidtestMany2OneGet(){

Orderorder=(Order)session.get(Order.class,1);

System.out.println(order.getCustomer().getClass().getName());

}

复制代码

Hibernate:

select

order0_.order_idasorder_id1_1_0_,

order0_.order_nameasorder_na2_1_0_,

order0_.customer_idascustomer3_1_0_

from

hibernate.orderorder0_

where

order0_.order_id=?

order1

com.nucsoft.hibernate.Customer_$$_jvst30c_1

复制代码

②查询n的一端,使用查询出来关联的1的一端的对象。

@Test

publicvoidtestMany2OneGet(){

Orderorder=(Order)session.get(Order.class,1);

System.out.println(order.getCustomer().getClass().getName());

order.getCustomer().getCustomerName();

}

复制代码

Hibernate:

select

order0_.order_idasorder_id1_1_0_,

order0_.order_nameasorder_na2_1_0_,

order0_.customer_idascustomer3_1_0_

from

hibernate.orderorder0_

where

order0_.order_id=?

com.nucsoft.hibernate.Customer_$$_jvst30c_1

Hibernate:

select

customer0_.customer_idascustomer1_0_0_,

customer0_.customer_nameascustomer2_0_0_

from

hibernate.customercustomer0_

where

customer0_.customer_id=?

复制代码

总结:

可以发现,采用的是懒加载机制,即获取到的1的一端的对象是一个代理对象。

只有在使用这个对象的属性的情况下,才会发送SQL语句。

③由懒加载机制引发的懒加载异常。

复制代码

@Test

publicvoidtestMany2OneGet(){

Orderorder=(Order)session.get(Order.class,1);

System.out.println(order.getCustomer().getClass().getName());

session.close();

order.getCustomer().getCustomerName();

}

复制代码

org.hibernate.LazyInitializationException:

couldnotinitializeproxy-noSession

在需要使用对象之前,关闭了Session连接,由此会引发LazyInitializationException异常。

2.双向的多对一

(1)还是以Order和Customer为例:

双向的多对一不仅仅要在Order类中定义一个Customer属性,而在Customer类中也需定义存放Order对象的集合属性。

(2)创建Order和Customer表和创建单向多对一相同。

(3)通过IntellijIdea生成简单的持久化类和Entity.hbm.xml文件。

手动的去建立关联关系。

<1>生成简单的持久化类和Entity.hbm.xml文件

 

Customer.java

Order.java

Customer.hbm.xml

Order.hbm.xml

<2>手动建立关联关系

①在Order一端建立多对一的关联关系。

在Order持久化类中添加Customer类型的一个属性customer。

在Order.hbm.xml文件中添加多对一的关联关系。

同时修改主键生成方式为native。

②在Customer一端建立一对多的关联关系。

在Customer持久化类中添加Order的一个集合orders。

在Customer.hbm.xml添加一对多的关联关系。

同时修改主键生成方式为native。

③详细说明:

在Customer.hbm.xml文件中添加一对多的关联关系。

当Session从数据库中加载Java集合时,创建的是Hibernate内置的集合类的实例。

因此在持久化类中定义集合属性时需要定义成接口类型,不能是具体的某个实现类。

Hibernate内置的集合具有集合代理功能,因为有代理功能,所以支持延迟检索策略。

  

在定义集合的时候,通常将其初始化为集合实现类的一个实例,防止NullPointerException。

Hibernate使用元素来映射Set类型的属性。

1的一端的Set类型属性数据还是存放在n的一端。

④set元素

 

name属性:

待映射的Set类型的属性的属性名称。

table属性:

待映射的Set属性的泛型类型所对应的表。

key子元素:

column属性,多的一端的外键名称。

one-to-many子元素:

class属性,n的一端的持久化类名称。

对应关系如图。

 

⑤最终的实体类和Entity.hbm.xml文件。

Customer.java

Order.java

Customer.hbm.xml

Order.hbm.xml

(4)通过IntellijIdea直接生成双向的多对一的关联关系。

 

<1>为生成的每个Entity.hbm.xml文件添加主键生成方式。

<2>为Customer类中的orders属性进行初始化。

<3>最终的持久化类和Entity.hbm.xml。

Customer.java

Order.java

Customer.hbm.xml

Order.hbm.xml

<4>对比发现,通过IntellijIdea自动生成的Customer.hbm.xml文件中set元素多了一个inverse属性。

稍后进行说明。

(5)双向多对一的CRUD和需要注意的问题

<1>新增

①双方都维护关联关系,即没有设置inverse属性,且没有添加非空约束。

先保存1的一端,再保存n的一端。

Save.java

打印SQL:

Output

结果:

打印了3条INSERT语句,2条UPDATE语句

先保存n的一端,再保存1的一端。

Save2.java

打印SQL:

Output2

结果:

打印了3条INSERT语句,4条UPDATE语句。

原因,双方都维护这关联关系。

②双方都维护关联关系,即没有设置inverse属性,对order表中的customer_id列添加非空约束(需要更改两个地方)。

先保存n的一端,再保存1的一端,会抛出异常。

org.hibernate.TransientPropertyValueException:

Not-nullpropertyreferencesatransientvalue-transientinstancemustbesavedbeforecurrentoperation:

com.nucsoft.hibernate.Order.customer->com.nucsoft.hibernate.Customer

③1的一端放弃维护关联关系,只由n的一端来维护。

即设置Customer.hbm.xml的set元素inverse属性值为true。

先保存1的一端,后保存n的一端。

Output

结果:

只会发送3条INSERT语句。

④总结:

介绍了双向的多对一的下的保存操作,若都维护关联关系,则会多出UPDATE语句。

且若外键存在非空约束时,不能先保存n的一端。

所以在进行Hibernate双向多对一保存的时候,最好的做法就是:

1的一端放弃维护关联关系,即设置set节点的inverse属性为true。

同时在保存的时候先保存1的一端,后保存n的一端。

<2>删除

Delete

同删除单向的多对一相同,会抛出异常:

com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException:

Cannotdeleteorupdateaparentrow:

aforeignkeyconstraintfails

存在外键约束。

<3>更新

Update

Output

<4>查询

@Test

publicvoidtestMany2OneBothGet(){

Customercustomer=(Customer)session.get(Customer.class,5);

System.out.println(customer.getOrders().getClass());

}

打印结果:

复制代码

Hibernate:

select

customer0_.customer_idascustomer1_0_0_,

customer0_.customer_nameascustomer2_0_0_

from

hibernate.customercustomer0_

where

customer0_.customer_id=?

classorg.hibernate.collection.internal.PersistentSet

复制代码

并没有查询关联的Order集合,实际类型为Hibernate内置的一个Set实现类。

证明了:

当Session从数据库中加载Java集合时,创建的是Hibernate内置的集合类的实例。

因此在持久化类中定义集合属性时需要定义成接口类型,不能是具体的某个实现类。

也证明了:

Hibernate内置的集合具有集合代理功能,因为有代理功能,所以支持延迟检索策略。

<5>说明

这里没有介绍cascade属性,是因为在实际的项目中,为了保护数据,很少设置cascade属性,而是手动去处理。

二、映射一对一关联关系。

1.这里只介绍双向的一对一关联关系如何映射。

单向的一对一只需要把没有外键的一端去掉就好了。

2.基于外键映射的双向一对一

(1)以Dempartment和Manager为例。

一个部门只能有一个经理,一个经理职能管理一个部门。

(2)创建Department和Manager表。

在Department表建立Manager表的外键。

department.sql

Manager.xml

(3)通过IntellijIdea自动生成的双向1对1无法映射列。

这里通过IntellijIdea生成简单的持久化类和Entity.hbm.xml文件,然后手动的添加映射。

Department.java

Manager.java

Department.hbm.xml

Manager.hbm.xml

(4)说明:

在department表中来维护外键。

在映射的时候选择元素,通过unique属性来达到一对一的效果。

在manager表中没有维护外键。

在映射时候选择元素,至于属性property-ref稍后在查询的时候说明。

(5)CRUD以及需要注意的地方。

<1>save

Save1.java

Output1

Save2.java

Output2

对比发现,先保存没有外键列的对象,会减少UPDATE语句的发送,提高性能。

<2>delete

Delete1.java

Output1

Delete2.java

Cannotdeleteorupdateaparentrow:

aforeignkeyconstraintfails(`hibernate`.`department`,CONSTRAINT`FK_kpcmf8csabfn9epikikcfqbk0`FOREIGNKEY(`manager_id_fk`)REFERENCES`manager`(`manager_id`))

外键关联对象存在的情况下,不能先删除拥有外键的对象。

<3>update

Update.java

Output

<4>get

Get1.java

Output1

可以看到,查询拥有外键对象关联的对象时,采用的还是懒加载机制。

此种情况下,若session关闭,再去调用关联对象的某个属性,会发生懒加载异常。

查询双向一对一中没有外键的一端:

Get2.java

复制代码

Hibernate:

select

manager0_.manager_idasmanager1_1_1_,

manager0_.manager_nameasmanager2_1_1_,

department1_.dept_idasdept1_0_0_,

department1_.dept_nameasdept2_0_0_,

department1_.manager_id_fkasmanager3_0_0_

from

hibernate.managermanager0_

leftjoin

hibernate.departmentdepartment1_

onmanager0_.manager_id=department1_.dept_id

where

manager0_.manager_id=?

com.nucsoft.hibernate.Manager@8ba

复制代码

复制代码

Hibernate:

select

manager0_.manager_idasmanager1_1_1_,

manager0_.manager_nameasmanager2_1_1_,

department1_.dept_idasdept1_0_0_,

department1_.dept_nameasdept2_0_0_,

department1_.manager_id_fkasmanager3_0_0_

from

hibernate.managermanager0_

leftouterjoin

hibernate.departmentdepartment1_

onmanager0_.manager_id=department1_.manager_id_fk

where

manager0_.manager_id=?

com.nucsoft.hibernate.Manager@8ba

复制代码

可以发现,在第一次查询时,没有设置property-ref属性。

左外链接查询时,虽然结果正确,但是连接条件不正确。

至于说,为什么查询Manager对象的时候,使用了左外链接而不是懒加载,因为Manager端没有Deparment的外键。

它不知道谁与它有关系。

只能通过左外链接查询一次查询。

3.基于主键的双向的一对一

(1)本质上和基于外键的双向一对一关联一样,只不过是以主键作为了外键来使用的。

(2)还是以Department和Manager为例。

(3)deparment表做了改动,因为是基于主键的映射,这里将department表中manager_id_fk去掉了。

(4)Department.hbm.xml和Manager.hbm.xml文件

复制代码

manager

复制代码

对于Department.hbm.xml文件,主键生成方式改为foreign,并且指定了主键生成所依赖的属性所对应的持久化类的主键生成方式。

需要注意的是,需要在节点添加constrained属性为true。

复制代码

复制代码

将Manager.hbm.xml文件的节点的property-ref属性去掉了。

(5)CRUD及需要注意的问题

<1>save

Save1.java

Save2.java

Output

结论:

发现不论是先保存department,还是先保存manager,都是先插入的manager。

因为department的主键生成方式是依赖于manager的。

<2>update

Update.java

Output

Update2.java

Output2

<3>get

Get.java

Output

通过department获取到的manager采用的是懒加载机制。

而从manager获取dept,是通过左外链接查询的。

至于原因,第一小点已经提到,本质上和基于外键的双向一对一关联一样,只不过是以主键作

展开阅读全文
相关资源
猜你喜欢
相关搜索
资源标签

当前位置:首页 > 党团工作 > 入党转正申请

copyright@ 2008-2023 冰点文库 网站版权所有

经营许可证编号:鄂ICP备19020893号-2