hibernate关联关系映射详解

词汇解释

关系:事物之间相互作用、相互联系的状态。范围最大。

联系:在关系数据库中表示实体与实体之间的联系,1:1,1:n,m:n。

关联:表示对象之间的关系,既有数量性,又有方向性;动词:将对象之间通过某种方式联系起来。

映射:这里指java对象和数据库表的一种对应关系。动词:形成这种对应关系。

级联:有关系的双方中操作一方,另一方也将采取一些动作。

关联的联系种类

在不考虑关联的方向前提下,联系就是关系数据库中表示实体与实体之间的联系,1:1,1:n,m:n。

一对一联系(1:1):如用户和身份证、一夫一妻

一对多联系(1:n):如班级和学生

多对多联系(m:n):如学生和选课

关联的方向

关联关系的方向可分为单向关联和双向关联。

双向关联的方向其实就不重要了,因为通过任一一方都可以维护彼此的关系。也就是说:在双向关联中一对多和多对一都是一样的。

单向关联

在关联标记例如<many-to-one>或者<one-to-many>,方向都是从左到右,换句话说是由左边维护它们的关系,参见下面例子。

假设存在两张表person表和address表,它们之间的联系是n:1;

即一个人的居住地址是唯一的,一个地址却可以多个人居住。

如果在应用的业务逻辑中,仅需要每个person实例能够查询得到其对应的Address实例,而Address实例并不需要查询得到其对应的person实例。

<class name="Person" table="person">
    <id name="id" >
        <generator class="native"/>
    </id>
    <many-to-one name="address"
        column="addressId"
        not-null="true"/>
</class>
<class name="Address" >
    <id name="id" column="addressId">
        <generator class="native"/>
    </id>
</class>

说明:

这是一个多对一的单向关联:由多的一方来维护它们的关系,需要在name="Person"的class元素内加入关联标记,<many-to-one>。这种关联非常多。

假设存在两张表person表和tel表,它们之间的联系是1:n;

即一个人的联系电话可能有多个,一个电话只能对应一个人。

如果在应用的业务逻辑中,我们仅仅关心每个person实例能够查询到其对应的所有tel实例,而tel实例并不需要查询得到其对应的person实例。

<class name="Person">
    <id name="id" column="personId">
        <generator class="native"/>
    </id>
    <set name="tels">
        <key column="personId" not-null="true" />
        <one-to-many class="Tel"/>
    </set>
</class>
<class name="Tel">
    <id name="id" column="telId">
        <generator class="native"/>
    </id>
</class>

说明:

这是一个一对多的单向关联:由一的一方来维护他们的关系,需要在name="Person"的class元素内加入关联标记,<one-to-many>。这种关联相对要少一些。大部分情况下我们都是操作多的一方的实例。

双向关联

在两边同时配置单向关联,就构成了双向管理。实际开发过程中,很多时候都是需要双向关联的,它在解决单向一对多维护关系的过程中存在的缺陷起了一定的修补作用。

假设存在两张表person表和address表,它们之间的联系是n:1;

即一个人的居住地址是唯一的,一个地址却可以多个人居住。

既需要每个person实例能够查询得到其对应的Address实例,Address实例也需要查询得到其对应的person实例。

<class name="Person">
    <id name="id" column="personId">
        <generator class="native"/>
    </id>
    <many-to-one name="address"
        column="addressId"
        not-null="true"/>
</class>
<class name="Address">
    <id name="id" column="addressId">
        <generator class="native"/>
    </id>
    <set name="people" inverse="true">
        <key column="addressId"/>
        <one-to-many class="Person"/>
    </set>
</class>

说明:

这是一个多对一双向关联。由双方维护彼此的关系。需要在name="Person"的class元素内加入关联标记,<many-to-one>。同时在name="Address"的class元素内加入集合映射<set>,并在其中加入关联标记:<one-to-many>。

关联标记

在hbm.xml中,关联标记<one-to-one>、<many-to-one>、<one-to-many>、<many-to-many>,关联的方向都是是从左到右。

关联标记属性

简单介绍下面几个,除了name是必须,其余都是可选的。更多的我们参考官文档。

name="对应本类的属性名"

column="映射到本表的字段名"

class="映射到本表的实体类"

unique="ture|false":(数据库外键字段生成一个唯一约束)

not-null="ture|false"默认false(数据库外键字段是否允许为空值)

lazy="ture|false"默认proxy(延迟加载)

关于cascade(级联)属性

级联的意思是指定两个对象之间的操作联动关系,对一个对象执行了操作之后,对其指定的级联对象也需要执行相同的操作

总共可以取值为:all、none、save-update、delete

all-代表在所有的情况下都执行级联操作

none-在所有情况下都不执行级联操作

save-update-在保存和更新的时候执行级联操作

delete-在删除的时候执行级联操作

集合映射标记<set>

<set name="peoples" inverse="true">
    <key column="addressId"/>
    <one-to-many class="Person"/>
</set>

<set name="peoples" inverse="true">name为持久化对象的集合的属性名称。

<key column="classid" > column外键的名称

<one-to-many class=“cn.edu.bzu.hibernate.Student" /> class持久化类

关于inverse属性

控制反转,主要用在一对多,多对对双向关联上,inverse可以设置到<set>集合上, 默认inverse为false。为true表示反转,由对方负责;反之,不反转,自己负责;如果不设,one和many两方都要负责控制,因此,会引发重复的sql语句以及重复添加数据。

谁是多谁是一

我们说一对一,多对一,多对多是谁对谁呢?在映射文件(.hbm.xml)中class元素中的对象关联标记中,比如<many-to-one>

那么class元素的属性name就是many,<many-to-one>标记中 name就是one。同时column="addressId"指明了person表的外键。

<class name="Person" table="person">
    <id name="id" >
        <generator class="native"/>
    </id>
    <many-to-one name="address"
        column="addressId"
        not-null="true"/>
</class>

上面例子中Person就是many,address就是one。

可以这么理解<many-to-one>在谁里面,谁就是many,<many-to-one>的属性name就是one。

单向关联hbm.xml配置

单向关联常用的是多对一

单向 many-to-one 关联是最常见的单向关联关系。这种关联是数据库关系模式中的多对一:

这个表的一个外键引用目标表的主键字段。

下面例子中的person与address联系(数据库用语)为n:1,可以这么理解:

即一个人的居住地址是唯一的,一个地址却可以多个人居住。

<class name="Person" table="person">
    <id name="id" >
        <generator class="native"/>
    </id>
    <many-to-one name="address"
        column="addressId"
        not-null="true"/>
</class>
<class name="Address" >
    <id name="id" column="addressId">
        <generator class="native"/>
    </id>
</class>

注意:<many-to-one>标签中column="addressId",为person表添加一个外键addressId。

sql输出:

create table Person ( personId bigint not null primary key, addressId bigint not null )
create table Address ( addressId bigint not null primary key )

双向关联hbm.xml配置

1.一对多/多对一

双向多对一关联 是最常见的关联关系。下面的例子解释了这种标准的父/子关联关系。

下面例子中的person与address联系(数据库用语)为n:1,可以这么理解:

即一个人的居住地址是唯一的,一个地址却可以多个人居住。

<class name="Person">
    <id name="id" column="personId">
        <generator class="native"/>
    </id>
    <many-to-one name="address"
        column="addressId"
        not-null="true"/>
</class>
<class name="Address">
    <id name="id" column="addressId">
        <generator class="native"/>
    </id>
    <set name="people" inverse="true">
        <key column="addressId"/>
        <one-to-many class="Person"/>
    </set>
</class>

注意:many-to-one关联需要将one的一端加入inverse="true";column="addressId"指明了person表的外键。

sql输出:

create table Person ( personId bigint not null primary key, addressId bigint not null )
create table Address ( addressId bigint not null primary key )

2.一对一

基于外键关联的双向一对一关联也很常见。

下面例子中person与address的联系(数据库用语)是1:1,可以这么理解:

即一个人只能管理一个地方,一个地方只能由一个人管理。

column="addressId"指明了person表的外键。

<class name="Person">
    <id name="id" column="personId">
        <generator class="native"/>
    </id>
    <many-to-one name="address"
        column="addressId"
        unique="true"
        not-null="true"/>
</class>
<class name="Address">
    <id name="id" column="addressId">
        <generator class="native"/>
    </id>
    <one-to-one name="person"
        property-ref="address"/>
</class>

sql输出:

create table Person ( personId bigint not null primary key, addressId bigint not null unique )
create table Address ( addressId bigint not null primary key )

使用连接表的关联

使用连接表的关联通常针对多对多。连接表会是数据中另外建的一张表,来存储两个实体的联系。

这张表有三个字段:本身的id,两个外键分别关联到两个实体的主键。

下面是student与course的联系(数据库用语)是m:n,可以这么理解:

一个学生可以选多门课程,一门课程也有多个学生。

<class name="Student">
    <id name="id" column="studentId">
        <generator class="native"/>
    </id>
    <set name="courses" table="StudentCourse">
        <key column="studentId"/>
        <many-to-many column="courseId"
        class="Course"/>
    </set>
</class>
<class name="Course">
    <id name="id" column="courseId">
        <generator class="native"/>
    </id>
    <set name="students" inverse="true" table="StudentCourse">
        <key column="courseId"/>
        <many-to-many column="studentId"
        class="Student"/>
    </set>
</class>

注意:<set>增加了table属性,因此会另外建表。

sql输出:

create table Student ( studentId bigint not null primary key )
create table StudentCourse ( studentId bigint not null, courseId bigint not null, primary key
(studentId, courseId) )
create table Course ( courseId bigint not null primary key )
时间: 2024-10-16 11:41:12

hibernate关联关系映射详解的相关文章

hibernate enum映射详解

hibernate enum映射详解 在这里介绍注解的形式,如果想要了解XML配置的方式,可以自行查找相关资料. 例如以下Entity @Entity @Table(name = "t_user") public class User implements Serializable { /** * */ private static final long serialVersionUID = -9042615274714038279L; @Id @GeneratedValue(stra

【Hibernate步步为营】--组合映射详解

上篇文章详细讨论了复合主键的映射原理,对于复合主键映射需要使用<composite-id>标签来标明映射的类属性,并在该标签中添加<key-property>子标签,并且主键列需要实现序列化接口,使用很简单只要学会如何进行映射就可以实现复合映射.接下来讨论组合对象映射,组合映射关系其实是把两个对象的公共部分抽象出来形成一个对象,两个子对象会包含另一个主对像,在配置映射文件时需要使用<component>标签来标明映射关系. 一.组合映射 组合是关联关系的一种特殊情况,是

【Hibernate步步为营】--双向关联一对一映射详解(二)

很不好意思,有两天时间没有更新博客文章了,不写文章的日子还真是感觉很空洞啊,养成了写文章的恶习想改也改不掉啊.说点题外话,前两天收到一位朋友的私信,邀请笔者写一篇有关OWS的文章,用来研究图标工具的一种技术,很荣幸收到这位朋友的邀请,但是因为这几天开发的项目着急上线所以暂时没有时间去研究,只能等这周末了,利用周末的时间来研究然后更新类似的技术文章. 回到文章的正题,上篇文章讨论了双向主键关联,它其实是一对一主键关联的一种特殊情况,想要实现双向的关联就必须在映射文件的两端同时配置<one-to-o

【Hibernate步步为营】--多对多映射详解

上篇文章详细讨论了一对多映射,在一对多映射中单向的关联映射会有很多问题,所以不建议使用如果非要采用一对多的映射的话可以考虑使用双向关联来优化之间的关系,一对多的映射其实质上是在一的一端使用<many-to-one>标签来标明它们之间的关系,另外还需要在一的一端的对象中使用set标明集合映射. 一.单向多对多 仍然按照前几篇的文章格式来讨论,首先来看对象之间的关系,单向的多对多关系是两个对象之间发生的,比如在人和职位之间,一个人可以有多个职位,而且一个职位也可以由多人来负责,所以它们之间就形成了

【Hibernate步步为营】--继承映射详解

上篇文章讨论了多对多映射,在使用多对多映射时重点是使用<many-to-many>标签,并在标签的两端加入外键这样在生成关系时会创建两个关系之间的关系表,通过关系表来维护它们之间的关系,另外对于单向和双向的区别是在映射的哪一端添加标签的问题.在面向对象中很重要的一个特性就是继承,继承实现了代码的复用,而且Hibernate把基本上所有的对象模型进行了映射封装,其中就包括继承映射,接下来就详细讨论. 一.继承映射 继承是面向对象很重要的特性,它实现了代码的服用,在关系模型中同样也有继承关系,这种

【Hibernate步步为营】--详解基本映射

Hibernate进行了分类整合发现其实Hibernate分为三大部分:核心对象.映射.HQL,这三大部分开发过程中最常使用,前几篇讨论了核心对象及对象之间的转换方法,接下来讨论Hibernate的映射使用方法. 一.基本用法 Hibernate一个重要的功能就是映射,它能够在对象模型和关系模型之间转换,是面向对象编程思想提倡使用的,使用映射程序开发人员只需要关心对象模型中代码的编写.对象和关系数据库之间的映射通常是由XML文档来定义的.这个映射文档被设计为易读的,并且可以手动修改.这种映射关系

【Hibernate步步为营】--双向关联一对一映射详解(一)

摘要:本文以我自己设计植物大战僵尸碰撞检测算法为例进行分析,浅谈游戏开发中碰撞检测算法.本文所提及的碰撞算法与数据结构也可应用于跑酷等游戏中. 关键优化技术1:只检测逻辑上可能存在碰撞关系的物体.比如植物大战僵尸中,植物发射的子弹只能打击其所在行的僵尸,因此子弹只需遍历检测本行的僵尸,而不是存在场景中的全部僵尸.对于地铁跑酷,奔牛跑酷,吃金币的碰撞检测算法亦是如此. 关键优化技术2:子弹检测碰撞僵尸,或是僵尸检测碰撞子弹,谁检测谁碰撞谁的问题,这个可能跟具体项目息息相关.可以从算法效率,以及设计

【Hibernate步步为营】--复合主键映射详解

本题是最基本的分段树操作了.或者一般叫线段树,不过好像和线段没什么关系,只是分段了. 不使用lazy标志,更新只是更新单点. 如果不使用分段树,那么更新时间效率只需要O(1),使用分段树更新效率就需要O(lgn)了. 但是不是用分段树,那么查询的时间效率是O(n),而分段树查询效率是O(lgn) 这就是amortize分摊了时间,而且lgn真的很快,数据不是非常巨大的时候,接近常数了. 故此本题需要使用分段树. #include <cstdio> class EnemyInfo { stati

【架构之路之ORM】--FluentNHibernate之基本映射详解

最近在做项目的时候用到了NHibernate,使用它并不困难,但是很麻烦.如果我的数据库有几百张表如果想要一个个的映射岂不是很麻烦,所以这种情况下使用NHibernate就会很笨重,虽然这个ORM框架本身功能强大,但属于重量级的在使用的时候太笨重了,所以需要在项目中改良.这时候就应运而生了FluentNHibernate,它是流畅版的NHibernate,支持所有的NHibernate功能,而且还封装了配置文件的映射功能,也就是说可以将映射使用C#代码编写,这样在维护时就会很简单. 在没有Flu