- 浏览: 103085 次
- 性别:
- 来自: 北京
-
文章分类
最新评论
关联关系分:单向关联(一对多、多对一)和双向关联(一对多双向)
在关系数据库中,只存在外键参照关系,而且总是由“many”方参照“one”方,因为这样才能消除数据冗余,因此关系数据库实际上只支持多对一或一对一的单项关联。
1、单向关联及级联保存和更新
Order 和 Customer存在多对一的关系,在Order映射文件中可以设置为:
<many-to-one
name="customer"
column="CUSTOMER_ID"
class="mypack.Customer"
not-null="true"/>
存在这样的使用方法:
Customer customer = new Customer("Jack");
//session.save(customer);
Order order1=new Order("Jack_Order001",customer);
Order order2=new Order("Jack_Order002",customer);
session.save(order1);//抛出PropertyValueException异常
session.save(order2);
抛出异常的原因:
save(order1)时,因为customer没有被持久化(在这种设置情况下,HIbernate不会自动持久化 Customer对象),所以对应的customerId=null,当保存时<many-to-one>设置 customer中的customerId为not-null,所以会出现异常。如果设置not-null="false",也会抛出异常:TransientObjectException,原因是order1的customer属性引用了一个临时对象Customer。
如果使用级联保存和更新那么可以解决这个问题:
<many-to-one
name="customer"
column="CUSTOMER_ID"
class="mypack.Customer"
cascade="save-update"
not-null="true"/>
这样Hibernate会自动持久化关联的临时对象。
2、映射一对多双向关联
既然是双向关联,实际上一对多还是多对一都是一回事,只是一对多比较顺口!
1中在Order中有了customer属性(多对一关系),可以直接在Order对象中获得所属的Customer,如果想知道该order所属的Customer的所有order,那么还需要通过一次查询才能获得。如果在Customer中添加Customer对Order的一对多关系,设为orders属性,那么就可以方便实现上述功能,调用 getOrders()方法即可,这就形成了双向关联。
注:Hibernate要求在持久化类中定义集合类属性时,必须把属性声明为接口类型,如:java.util.set、java.util.Map、java.util.List。这样可以提高持久化类的透明性。
在定义集合属性时,通常把他初始化为集合实现类的一个实例,private Set orders = new HashSet();这样可以提高程序的健壮性,避免因为null而抛出异常。
映射方法:
<set name="orders" cascade="save-update">
<key column="CUSTOMER_ID"/>
<one-to-many class="myapck.Order"/>
</set>
当建立order对象和customer对象的双向关联关系时,需要在程序中同时修改两个对象的属性:
-建立Order到Customer对象的多对一关系
order.setCustomer(customer)
hibernate探测到这个变化后会将order对应的CUSTOMER_ID的值改为customer的id,会执行SQL:
update ORDERS set ORDER_NUMBER="Jack_Order001",CUSTOMER_ID=2 where ID=2;
-建立Customer对象到Order对象的一对多关联关系:
customer.getOrders().addOrder(order);
hibernate探测到这个变化后也会将order对应的CUSTOMER_ID的值改为customer的id,会执行SQL:
update ORDERS set CUSTOMER_ID=2 where ID=2;
这样会重复执行多余的SQL,影响性能。解决这一问题的方法是把<set>元素的inverse属性设置为true,默认为false;
<set name="orders" cascade="save-update" inverse="true">
<key column="CUSTOMER_ID"/>
<one-to-many class="myapck.Order"/>
</set>
这样设置以后,如果只执行:order.setCustomer(customer),同样会自动更新order记录
但是如果只执行:customer.getOrders().addOrder(order);却不会自动更新order记录,这是因为在Customer 对象的orders属性映射中<set>元素设置了inverse = true;所以hibernate不会同步更新数据库:
结论:
--在映射一对多的双向关联关系时,应该在“many”方(orders属性)把inverse属性设置为"true",这样可以提高应用的性能。
--在建立两个对象的双向关联时,应该同时修改关联两端的对象的相应属性:
customer.getOrders().addOrder(order);
order.setCustomer(customer)
同理,解除双向关联的关系时,也应该修改关联两端的对象的属性:
customer.getOrders().remove(order);
order.setCustomer(null);
------------------------------------------------------------------------------------------------------------
多对一(many-to-one)
通过many-to-one元素,可以定义一种常见的与另一个持久化类的关联。 这种关系模型是多对一关联(实际上是一个对象引用-译注):这个表的一个外键引用目标表的 主键字段。
<many-to-one
name="propertyName"
column="column_name"
class="ClassName"
cascade="cascade_style"
fetch="join|select"
update="true|false"
insert="true|false"
property-ref="propertyNameFromAssociatedClass"
access="field|property|ClassName"
unique="true|false"
not-null="true|false"
optimistic-lock="true|false"
lazy="proxy|no-proxy|false"
not-found="ignore|exception"
entity-name="EntityName"
formula="arbitrary SQL expression"
node="element-name|@attribute-name|element/@attribute|."
embed-xml="true|false"
index="index_name"
unique_key="unique_key_id"
foreign-key="foreign_key_name"
/>
1
name: 属性名。
2
column (可选): 外间字段名。它也可以通过嵌套的 <column>元素指定。
3
class (可选 - 默认是通过反射得到属性类型): 关联的类的名字。
4
cascade(级联) (可选): 指明哪些操作会从父对象级联到关联的对象。
5
fetch (可选 - 默认为 select): 在外连接抓取(outer-join fetching)和序列选择抓取(sequential select fetching)两者中选择其一。
6
update, insert (可选 - 默认为 true) 指定对应的字段是否包含在用于UPDATE 和/或 INSERT 的SQL语句中。如果二者都是false,则这是一个纯粹的 “外源性(derived)”关联,它的值是通过映射到同一个(或多个)字段的某些其他属性得到 或者通过trigger(触发器)、或其他程序生成。
6
property-ref: (可选) 指定关联类的一个属性,这个属性将会和本外键相对应。 如果没有指定,会使用对方关联类的主键。
7
access (可选 - 默认是 property): Hibernate用来访问属性的策略。
8
unique (可选): 使用DDL为外键字段生成一个唯一约束。此外, 这也可以用作property-ref的目标属性。这使关联同时具有 一对一的效果。
9
not-null (可选): 使用DDL为外键字段生成一个非空约束。
10
optimistic-lock (可选 - 默认为 true): 指定这个属性在做更新时是否需要获得乐观锁定(optimistic lock)。 换句话说,它决定这个属性发生脏数据时版本(version)的值是否增长。
11
lazy (可选 - 默认为 proxy): 默认情况下,单点关联是经过代理的。lazy="no-proxy"指定此属性应该在实例变量第一次被访问时应该延迟抓取(fetche lazily)(需要运行时字节码的增强)。 lazy="false"指定此关联总是被预先抓取。
12
not-found (可选 - 默认为 exception): 指定外键引用的数据不存在时如何处理: ignore会将行数据不存在视为一个空(null)关联。
13
entity-name (可选): 被关联的类的实体名。
14
formula (可选): SQL表达式,用于定义computed(计算出的)外键值。
cascade属性设置为除了none以外任何有意义的值, 它将把特定的操作传递到关联对象中。这个值就代表着Hibernate基本操作的名称, persist, merge, delete, save-update, evict, replicate, lock, refresh, 以及特别的值delete-orphan和all,并且可以用逗号分隔符 来组合这些操作,例如,cascade="persist,merge,evict"或 cascade="all,delete-orphan"。更全面的解释请参考第 10.11 节 “传播性持久化(transitive persistence)”. 注意,单值关联 (many-to-one 和 one-to-one 关联) 不支持删除孤儿(orphan delete,删除不再被引用的值).
一个典型的简单many-to-one定义例子:
<many-to-one name="product" class="Product" column="PRODUCT_ID"/>
property-ref属性只应该用来对付遗留下来的数据库系统, 可能有外键指向对方关联表的是个非主键字段(但是应该是一个惟一关键字)的情况下。 这是一种十分丑陋的关系模型。比如说,假设Product类有一个惟一的序列号, 它并不是主键。(unique属性控制Hibernate通过SchemaExport工具进行的DDL生成。)
<property name="serialNumber" unique="true" type="string" column="SERIAL_NUMBER"/>
那么关于OrderItem 的映射可能是:
<many-to-one name="product" property-ref="serialNumber" column="PRODUCT_SERIAL_NUMBER"/>
当然,我们决不鼓励这种用法。
如果被引用的唯一主键由关联实体的多个属性组成,你应该在名称为<properties>的元素 里面映射所有关联的属性。
假若被引用的唯一主键是组件的属性,你可以指定属性路径:
<many-to-one name="owner" property-ref="identity.ssn" column="OWNER_SSN"/>
------------------------------------------------------------------------------------------------------------
3、级联删除
如果在删除customer的时候,将其关联的orders也删除只需要设置cascade=delete
<set name="orders" casecade="delete" inverse="true">
<key column="CUSTOMER_ID"/>
<one-to-many class="myapck.Order"/>
</set>
4、父子关系
解除customer与其中一个order之间的关系:
tx=session.beginTransaction();
Customer customer=(Customer>session.load(Customer.class,new Long(2));
Order order = (Order)customer.getOrders().iterator().next();
customer.getOrders().remove(order);
order.setCustover(null);
tx.commit();
如果cascade取默认值“none”,当order.setCustomer(null)时,会执行:
update ORDERS set CUSTOMER_ID = null where ID=2;
如果希望Hiernate自动删除不再和customer对象关联的order对象,可以把cascade属性设置为"all-delete-orphan"
<set name="orders" cascade="all-delete-orphan" inverse="true">
<key column="CUSTOMER_ID"/>
<one-to-many class="myapck.Order"/>
</set>
此时如果执行order.setCustomer(null)会执行一下SQL:
delete from ORDERS where CUSTOMER_ID=2 and ID=2;
cascade="all-delete-orphan"时Hibernate会按以下方式处理Customer对象:
--当保存或更新Customer对象时,级联保存或更新所有关联的Order对象,相当于cascade="save-update"
--当删除Customer对象时,级联删除所有关联的Order对象,相当于cascade="delete"
--删除不再和Customer对象关联的所有Order对象。
总结:
当关联双方存在父子方系,就可以把父方的cascade属性设置为"all-delete-orphan"。所谓父子关系,是指由父方来控制子方的持久化生命周期,子方对象必须和一个父方对象关联。如果删除父方对象,应该级联删除所有的关联子方对象,如果一个子方对象不再和一个父方对象关联,应该把这个子方对象删除。
5、一对多双向自身关联关系
考虑以下情形:Category表
每个Category可能有其(0或1个)父类和(多个子类),其映射文件如下:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping
PUBLIC "-//Hibernate/Hibernate Mapping DTD 2.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd">
<hibernate-mapping >
<class name="mypack.Category" table="CATEGORIES" >
<id name="id" type="long" column="ID">
<generator class="increment"/>
</id>
<property name="name" type="string" >
<column name="NAME" length="15" />
</property>
<set
name="childCategories"
cascade="save-update"
inverse="true"
>
<key column="CATEGORY_ID" />
<one-to-many class="mypack.Category" />
</set>
<many-to-one
name="parentCategory"
column="CATEGORY_ID"
class="mypack.Category"
/>
</class>
</hibernate-mapping>
表数据:
父类别的映射为:
<many-to-one
name="parentCategory"
column="CATEGORY_ID"
class="mypack.Category"
/>
原理:
<many-to-one>表示多个该类对象对应一个父类别。[以外键匹配主键]
<many-to-one>元素表示以"CATEGORY_ID"作为外键与"mypack.Category"对应的表的主键去匹配,如果存在则是父类别。
如:表中的food,CATEGORY_ID=null所以没有父类别,与图相符,vegetable和fruit的父类是food;
子类别的映射:
<set
name="childCategories"
cascade="save-update"
inverse="true"
>
<key column="CATEGORY_ID" />
<one-to-many class="mypack.Category" />
</set>
原理:
<one-to-many>表示单个该类对象对应多个子类别;[以主键去匹配外键]
<one-to-many>元素表示以该记录对应的表的主键(ID)去匹配"mypack.Category"对应的表中的"CATEGORY_ID"字段;
发表评论
-
Hibernate入门
2010-10-27 00:11 735Java代码 1.public class User { ... -
hibernate二级缓存攻略
2010-10-20 15:31 619很多人对二级缓存都不太了解,或者是有错误的认识,我一直想写一篇 ... -
精通hibernate学习笔记(8-2)[检索方式]
2010-10-19 13:01 7414、报表查询 报表查询用于对数据分组和统计,完整的HQL语 ... -
精通hibernate学习笔记(8)[检索方式]
2010-10-19 13:00 793提供的检索方式: (1)导航对象图检索方式 (2)OID ... -
精通hibernate学习笔记(7)[检索策略]
2010-10-19 12:55 812Customer和Order为例 1、hibernate检索 ... -
精通hibernate学习笔记(6)[映射类型]
2010-10-19 12:51 776Hibernate映射类型分为两种:内置映射类型和客户化映射类 ... -
精通hibernate学习笔记(4)[操作持久化对象]
2010-10-19 12:47 7141、理解Session的缓存 如果希望一个java对象一直处 ... -
精通hibernate学习笔记(5)[映射组成关系]
2010-10-19 12:46 8791、概念 1.1 聚集关系 在域模型中,有些类由几个 ... -
精通hibernate学习笔记(2)[标志符生成器]
2010-10-19 12:37 5941、increment 标识符生成器 该生成器由Hiber ... -
精通hibernate学习笔记(1)
2010-10-19 12:36 774实体域对象的 持久化模式 1、ORM模式 对象-关 ... -
分析Hibernate的缓存机制
2010-10-19 12:33 628缓存是介于应用程序和 ... -
Hibernate缓存管理
2010-10-19 12:31 6081. Cache简介: 缓存( ... -
Hibernate 学习笔记
2010-10-19 12:28 805原创 hibernate 笔记 收藏 day1 一. h ...
相关推荐
Hibernate学习笔记 Hibernate学习笔记 Hibernate学习笔记 Hibernate学习笔记
Hibernate学习笔记整理 以下是 Hibernate 框架的详细知识点: Hibernate 介绍 Hibernate 是一个 ORM(Object-Relational Mapping)框架,用于将 Java 对象映射到数据库表中。它提供了一个简洁的方式来访问和操作...
《Hibernate学习笔记特别详细》 Hibernate,作为一款开源的Object-Relational Mapping(ORM)框架,为Java开发者提供了强大的数据库操作支持。它简化了数据库访问的复杂性,使得开发人员可以像操作对象一样操作...
hibernate 学习笔记精要hibernate 学习笔记精要hibernate 学习笔记精要hibernate 学习笔记精要
在本篇《Hibernate学习笔记》中,我们将深入探讨Hibernate这一流行的Java对象关系映射(ORM)框架。Hibernate允许开发者以面向对象的方式处理数据库操作,极大地简化了数据存取的复杂性。以下是一些关键知识点: 1....
【标题】:“精通Hibernate读书笔记” 【描述】:本笔记主要涵盖了Hibernate的使用、概念以及在Java应用程序中的重要性。 【标签】:Hibernate 【正文】: Hibernate是Java应用程序与关系数据库之间的一种中间件...
在实体类之间,Hibernate支持多种关联关系,包括一对一(One-to-One)、一对多(One-to-Many)和多对多(Many-to-Many)。本资源主要探讨的是“hibernate一对一关联关系”。 一对一关联关系在现实世界中很常见,...
这套笔记是我学习Hibernate,进行相关技术点训练时记录下来的,其中包括技术点说明与相关事例,拿出来与大家分享。
【Java相关课程系列笔记之十四Hibernate学习笔记】 Hibernate是一个开源的对象关系映射(ORM)框架,它极大地简化了Java应用程序对数据库的操作。本笔记将详细阐述Hibernate的核心概念、使用方法和特性。 一、...
标题:Hibernate学习笔记3 描述:本篇笔记深入探讨了Hibernate框架中一对多关系的映射及持久化对象状态管理,结合个人理解与实践经验,旨在为读者提供一份详实的学习资料。 ### 一、一对多关系映射详解 在...
《Hibernate学习笔记——马士兵教程解析》 在Java开发领域,ORM(Object-Relational Mapping)框架的使用已经非常普遍,其中Hibernate作为一款优秀的ORM框架,因其强大的功能和易用性深受开发者喜爱。本文将根据马...
本主题将深入探讨Hibernate集合映射与关联关系,包括"student与Score的Map集合关系"、"student与class的多对一"以及"一对多映射"的概念。 首先,让我们理解一下Hibernate中的集合映射。在关系型数据库中,一个实体...
总的来说,“精通Hibernate源码Chapter 3”涵盖了对象持久化的基础理论和实践技巧,通过学习源码,开发者能够更深入地理解Hibernate的工作机制,提高开发和调试的效率。在实际项目中,熟练掌握Hibernate不仅能够简化...
**Hibernate学习笔记与总结** Hibernate 是一款开源的对象关系映射(ORM)框架,它为Java开发者提供了一种在关系数据库上操作对象数据的便捷方式。本文将深入探讨Hibernate的核心概念、配置、实体类、映射文件、...
《马士兵Hibernate学习笔记》是一份深入浅出的教程,旨在帮助初学者掌握Hibernate这一流行的Java持久化框架。Hibernate是一个对象关系映射(ORM)工具,它允许开发者用面向对象的方式来操作数据库,从而减少了传统...
这篇文档和学习笔记将深入介绍Hibernate的核心概念、API用法以及最佳实践。 1. **Hibernate核心概念** - **对象关系映射(ORM)**: Hibernate是ORM的一种实现,它允许开发者使用面向对象的方式来操作数据库,而...
hibernate中一对一,一对多,多对多关系的配置,延迟加载,cascade,inverse hibernate查询方式概述,HQL查询,QBC查询,分页,结果集封装方式 ,高级查询 查询的优化,一级缓存,二级缓存,批量查询,注解方式
总结,Hibernate3作为强大的O/R Mapping框架,通过对象关系映射简化了数据库操作,提高了开发效率,并提供了丰富的查询机制和最佳实践建议。学习和掌握Hibernate有助于提升Java应用的数据管理能力。