Hibernate 的基本映射

本文深入探讨了ORM技术中各种集合属性的映射方法,包括List、Set、Bag和Map等,以及引用属性的映射技巧。同时介绍了主键生成器的不同策略,并详细解释了复合主键的映射方式。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、主键生成器
主键生成器是负责生成数据表记录的主键,通常有如下几种常见的主键生成器。
increment: 对long , short 或int 的数据列生成自动增长主键。
identity: 对如SQL server, MySQL 等支持自动增长列的数据库,如果数据列的类型是long , short 或int,可使用主键生成器生成自动增长主键。
sequence: 对如Oracle , DB2 等支持Sequence 的数据库,如果数据列的类型是long ,short 或int ,可使用该主键生成器生成自动增长主键。
uuid: 对字符串列的数据采用128-位uuid 算法生成唯一的字符串主键。
二、映射集合属性
1. List 集合属性
List 是有序集合,因此持久化到数据库时也必须增加一列来表示集合元素的次序。看下面的持久化类,该Person 类有个集合属性: schools,该属性对应多个学校。而集合属性只能以接口声明,因此在下面的代码中,schools 的类型只能是List,不能是ArrayList ,但该集合属性必须使用实现类完成初始化。
public class Person implements Serializable
{
      II 标识属性
      private int id;
      II名字属性
      private String name;
      II集合属性,学校
      private List schools = new ArrayList();
}
该持久化类的普通属性的映射与前面相同,不同的是增加了集合属性。对本例的List集合属性,应该使用list 元素完成映射, list 元素要求用list-index 的子元素来映射有序集合的次序列。集合属性的值会存放在另外的表中,不可能与持久化类存储在同一个表内。因此必须以外键关联,用key 元素来映射该外键列
下面是该持久化类的映射文件:
<?xml vers工on= 1I 1.0"?>
<!一Hibernate映射文件的文件头,包含DTD 等信息-->
<!DOCTYPE hibernate-mapping
PUBL工C "-IIHibernatel丑工bernate Mapping DTD 3.01IEN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.O.dtd">
<! -- H 工bernate 映射文件的根元素一〉
<hibernate-mapping package="lee">
<!-- 每个class 元素映射一个持久化类>
<class name="Person">
<!-- 定义持久化类的标识属性->
<id n缸ne="id" column="personid">
<!-- 定义主键生成器策略一〉
<generator class="identity"l>
<lid>
<!一映射普通属性name-->
<property name="name"l>
<!一映射普通属性age-->
<property name="age"l>
<!- 映射集合属性schools,指定存放集合属性的表名->
<list name="schools" table="school">
<!- 集合属性和持久化类的关联外键>
<key column="personid" not-null="true"l>
<!-- 集合属性的次序列一〉
<list-index column="list_order"l>
<!-- 集合属性的元素一〉
<element type="string" column="school_name"l>
</list>
</class>
</hibernate-mapping>
2. Set 集合属性
Set 集合属性的映射与Li st 非常相似,但因为Set 是无序的,不可重复的集合。因此set 元素无须使用index 元素来指定集合元素的次序。与List 相同的是, Set 集合同样需要外键列。用于持久化类和集合属性的关联。Set集合属性声明时,只能使用Set 接口,不能使用实现类。可将上面示例的List 集合属性改为Set 集合属性,此处不再赘述。
映射文件也与List 集合属性的映射相似,区别在于使用set 元素时,无须增加index列来保存集合元素的次序。下面是Set 集合属性的映射文件:
<?xml version="1.0"?>
<!-- Hibernate 的映射文件的文件头,包含DTD 等信息一〉
<!DOCTYPE hibernate-mapping
PUBLIC "< IIHibernate/Hibernate Mapp工ng DTD 3.01IEN"
''http://hibernate.sourceforge.net/hibernate-mapping-3.O.dtd">
<!-- Hibernate 映射文件的根元素一〉
<hibernate-mapp工ng package="lee">
<!一每个class 元素映射→个持久化类一〉
<class name="Person">
<! .-- 映射标识属性一〉
<id name="id" column="personid">
<'一指定主键生成器一〉
<generator class="identity"l>
<lid>
<!一映射name 属性一〉
<property name="name"l>
<!一映射age 属性〉
<property name="age"l>
<!-- 映射Set 集合属性,指定集合属性存入school 表…〉
<set name="schools" table="school">
<l 二集合属性的外键列-->
<key column="personid" not-null="true"l>
<!一用于映射集合中的元素>
<element type="string" column="school_name" not-null="true"l>
</set>
</class>
</hibernate-mapping>
3. bag 元素映射
bag 元素既可以为Li st 集合属性映射,也可以为Collection 集合属性映射。不管是哪种集合属性,使用bag 元素都将被映射成无序集合,而集合属性对应的表没有主键。bag 元素只需要key 元素来映射关联的外键列,而使用element 元素来映射集合属性的每个元素。
下面是持久化类使用bag 元素的映射文件代码:
<?xml version="l.O"?>
< J -- Hibernate映射文件的文件头,包含DTD 等信息-→
<!DOCTYPE hibernate-mapping
PUBLIC "-IIHibernate/Hibernate Mapping DTD 3.01IEN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.O.dtd">
<! -- Hibernate 映射文件的根元素一〉
<hibernate-mapping package="lee">
<!一每个class 元素映射一个持久化类-->
<class name="Person">
<! -- id 元素映射标识属性一〉
<id name="id" column="personid">
<'一指定主键生成器策略…〉
<generator class="identity"l>
<lid>
<!… 映射name 属性-->
<property name="name"/>
<1- 映射age 属性…〉
<property name="age"l>
<1-- 映射集合属性-->
<bag name="schools" table="school">
<key column="personid" not-null="true"/>
<element type="string" column="school_name"/>
</bag>
</class>
</hibernate-mapping>
4. Map 集合属性
Map 集合属性不仅需要映射属性value ,还需要映射属性key 。映射Map 集合属性时,同样需要指定外键列,同时还必须指定Map 的key 列。显然,系统将以外键列和key 列作为联合主键。与所有集合属性类似的是,集合属性的声明只能使用接口,看下面的POJO 类:
private Map scores = new HashMap();
Map 集合属性应使用map 元素映射,该map 元素需要key 和map-key 两个子元素。
其中key 子元素用于映射外键列,而map-key 子元素则用于映射Map 集合的Key。该持
久化类的映射文件如下:
<?xml version="1.0"?>
<!-- Hibernate 映射文件的文件头,包含DTD 信息-->
<!DOCTYPE hibernate-mapping
PUBL工C "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
''http://hibernate.sourceforge.net/hibernate-mapping-3.O.dtd">
<!一Hibernate映射文件的根元素->
<hibernate-mapping package="lee">
<! 每个class 元素映射一个持久化类-->
<class name="Person">
<!-- id 元素用于映射标识属性>
<id name="id" column="personid">
<'一指定主键生成器策略一〉
<generator class="identity"/>
<lid>
<!-- 映射name 属性-->
<property name="name"/>
<!-- 映射age 属性…〉
<property name="age"/>
<!-- 映射Map 集合属性>
<map name="scores" table="score">
<'一映射外键J"tl-->
<key column="personid" not-null="true"/>
<'一映射Map Key-->
<map-key column="xueke" type="string"/>
<!一映射Map Value-->
<element column="fenshu" type="float"/>
</map>
</class>
</hibernate-mapping>
程序运行结束后,保存集合属性scores 的表,并以personid 和xueke 作为联合主键。
注意: map-key 和element 元素都必须确定type 属性。
Hibernate 对集合属性默认采用延迟加载,在某些特殊的情况下为set, list, map 等元素设置lazy= "false" 属性来取消延迟加载。
根据前面的讲解,可将集合分成如下两类。
·有序集合:集合里的元素可以根据key 或index 访问。
·无序集合:集合里的元素只能遍历。
有序集合都拥有一个由<key>和<index>组成的联合主键,在这种情况下,集合属性的更新是非常高效的一一主键已经被有效地索引。因此当Hibernate 试图更新或删除某行时,可以迅速找到该行数据。而对无序集合而言,如果集合中元素是组合元素或者大量文本及二进制宇段,数据库可能无法有效地对复杂的主键进行索引。即使可以建立索引,性能也非常差。例如Set的主键由<key>和其他元素宇段构成,或者根本没有主键。显然,有序集合的属性在增加、删除及修改中拥有较好的性能表现。
在设计良好的Hibernate Domain Object 中,集合属性通常都会增加inverse="true"的属性,此时集合端不再控制关联关系。因此,无须考虑其集合的更新性能。
三、映射引用属性
为了映射引用属性, Hibernate提供了component元素。每个component元素映射一个引用属性,引用属性必须指定该属性的类型。因此componet元素要求具有class 属性,该属性用于确定引用属性的类型。
一个自定义类通常还包括其他属性,因此还应该为component 元素增加property 的子元素来映射引用属性的子属性。下面是持久化类的映射文件:
<?xml version="1.0"?>
<'一Hibernate 映射文件的文件头,包含DTD 信息一〉
<lDOCTYPE hibernate-mapping
PUBLIC "-IIHibernate/Hibernate Mapping DTD 3.OIIEN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.O.dtd">
<! -- Hibernate 映射文件的文件头…〉
<hibernate-mapping package="lee">
<!一每个class 元素映射一个持久化类一〉
<class name="Person" table="person">
<l-- id 属性映射标识属性一〉
<id name:;;: lI id" colurnn="persoD_id">
<!一指定主键生成器策略一〉
<generator class="increment"l>
<lid>
<!一映射普通属性age-->
<property name="age"l>
<!一映射引用属性name,引用属性的类型为Name ?
<component name="name" class="Name" unique="true">
<!- 映射引用属性的f 工rst 属性一〉
<property name="first"/>
<!-- 映射引用属性的last 属性-->
<property name="last"/>
</component>
</class>
</hibernate-mapping>
映射文件中的component还有unique= "true" 属性,这并不是必需的,而是与具体的业务逻辑相关联的。
引用属性还有如下两种特殊的情况:
·集合属性的元素既不是基本数据类型,也不是String 字符串,而是引用类型。
·持久化类的主键是引用类型。
下面对这两种情况具体分析。
1. 集合引用属性映射
对于有集合属性的POJO,都需要使用set, list, bag 等集合元素来映射集合属性。如果集合里的元素是普通宇符串,则使用element 映射集合元素即可。如果集合元素是自定义类,则须使用composite-element 子元素来映射集合元素。由于composite-element 元素映射一个引用类型,因此需要增加class 元素来确定集合元素的类型,该元素还支持以property 的子元素来定义引用类型的子属性。
下面是Person 类的持久化映射文件:
<?xml version="l.O"?>
<!一Hibernate映射文件的文件头,包含DTD 等信息二〉
<!DOCTYPE hibernate-mapping
PUBLIC "-IIHibernate/Hibernate Mapping DTD 3.01IEN"
''http://hibernate.sourceforge.net/hibernate-mapping-3.O.dtd">
<'一Hibernate 映射文件的根元素->
<hibernate-mapping package="lee">
<!一每个class 元素映射一个持久化类-->
<class name="Person">
<'一id 属性映射…〉
<id name="id" column="personid">
<!-- 指定主键生成器策略->
<generator class="identity"l>
<lid>
<!… 映射普通属性口ame-->
<property name="name"l>
<!… 映射普通属性age-->
<property name="age"l>
<! 映射List 集合属性一〉
<list name="schools" table="school">
<!… 映射关联外键列-->
<key column="personid" not-null="true"l>
〈List 有序集合,需要索引列一〉
<list-index column="list_order"l>
<!-- composite-element映射集合里的元素, class 属性确定集合里元素的类型-->
<composite-element class="School">
<!一每个property属性映射集合元素的基本属性-->
<property name="name"/>
<property name="address"/>
</composite-element>
</list>
</class>
</hibernate-mapping>
2. 引用类型主键的映射
Person 的标识属性不再是基本数据类型,也不是String 字符串,而是Name 类型,该类型是用户自定义的类型。
如果持久化类需要使用引用类型作为表示属性时,则该类应该满足如下两个条件:
.实现java.io.Seria1izable 接口。
·重写equalsO和hashCodeO方法,这两个方法的返回值都应该根据数据表中联合主键的列来判断。
对于Person 持久化类,其Name 是标识属性的类, Name 实例可以唯一标识Person实例。根据业务需要,能唯一标识Person 实例的应该是firstName 和lastName 两个属性。因此hashCode 和equals 方法都应根据firstName和lastName 两个属性来判断。引用类型主键的映射时,应使用composite-id元素,该元素需要class 属性来确定主
键的引用类型,并使用key-property元素来确定引用类型包含的基本属性。
<?xml version="1.0"?>
<!-- Hibernate 映射文件的文件头,包含DTD 等信息>
<!DOCTYPE hibernate-mapping
PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
''http://h工bernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!一Hibernate 映射文件的根元素>
<hibernate-mapping package="lee">
<!一每个class 元素映射一个持久化类-->
<class name="Person" table="person">
<!-- componsite-id元素用于映射引用类型的标识属性,其中class 元素确定属性的类型>
<composite id name="name" class="Name">
<key-property元素确定标识属性类包含的属性〉
<key-property name="firstName"/>
<key-property name="lastName"/>
</composite-id>
<property name="age"/>
</class>
</hibernate-mapping>
3. 复合主键的映射
映射复合主键的持久化类必须满足如下两个条件。
·实现java .io.Serializable 接口。
·重写equalsO和hashCodeO方法,两个方法的返回值应该根据数据表中的联合主键来判断。
如需映射firstName 和lastName 两个标识属性时,同样可使用composite-id 元素,
此时的composite-id元素不需要name 和class 属性,因为标识属性既没有实现类,也不
是一个真实存在的属性。
看下面的映射文件源代码:
<?xml version="1.0"?>
<!一Hibernate 映射文件的文件头,包含DTD 等信息>
<lDOCTYPE hibernate-mapping
PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
''http://hibernate.sourceforge.net/hibernate-mapping-3.O.dtd">
<1 … Hibernate 映射文件的根元素一〉
<hibernate-mapping package="lee">
<!-- 每个class 元素映射一个持久化类->
<class name="Person" table="personcomid">
<1-- composite-id用于映射复合主键一〉
<composite-id>
<! -- key-property元素映射复合主键的每个元素>
<key-property name="firstname"/>
<key-property name="lastname"/>
</composite-id>
<property name="age"/>
</class>
</hibernate-mapping>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值