Hibernate映射之基本类映射和对象关系映射详解

回想一些我们在没有学习ssh的时候,我们建立数据库的表时,首先是数据库建模E-R图,然后再通过实体模型来建立关系模型,再建立相应的表。实体间存在三种关系,一对一,一对多(或者说多对一),多对多。而如今我们要根据类来映射相应的表,那只能是通过类与类之间的关系加上映射文件来映射数据库的表。我们学习UML建模,类与类之间存在五种关系,继承,实现,关联,依赖,聚合/组合,在hibernate中实体类之间的关系也是如此,对于不同的关系对应的代码实现我们已经很熟悉了,所以对于实体类是复习的知识。

Hibernate的本质就是对象关系映射(ObjectRelational Mapping),ORM实现了将对象数据保存到数据库中,以前我们对关系表进行操作,执行增删改查等任务,现在我们不再对关系表进行操作,而是直接对对象操作。hibernate中的ORM映射文件通常以.hbm.xml作为后缀。使用这个映射文件不仅易读,而且可以手工修改,也可以通过一些工具来生成映射文档。下面将对hibernate中的映射进行介绍。

Hibernate映射分类,如下图所示。

1 基本类映射

根据实体类创建相应的表,这种简单的关系为hibernate基本映射。

User1实体类代码如下:

//user实体。
public classUser1 {
  //用户编号。
  private String id; 

  //名字。
  private String name; 

  //密码。
  private String password; 

  //创建日期。
  private Date createTime; 

  //失效时间。
  private Date expireTime; 

  public String getId() {
   return id;
  } 

// publicvoid setId(String id) {
//  this.id= id;
// } 

  public String getName() {
   return name;
  } 

  public void setName(String name) {
   this.name = name;
  } 

  public String getPassword() {
   return password;
  } 

  public void setPassword(Stringpassword) {
   this.password = password;
  } 

  public Date getCreateTime() {
   return createTime;
  } 

  public void setCreateTime(DatecreateTime) {
   this.createTime = createTime;
  } 

  public Date getExpireTime() {
   return expireTime;
  } 

  public void setExpireTime(DateexpireTime) {
   this.expireTime = expireTime;
  }
 }

User1.hbm.xml映射文件如下所示:

<hibernate-mapping package="com.bjpowernode.hibernate"> 

  <class name="User1" table="t_user1">
   <id name="id"column="user_id" length="32"access="field">
     <generator class="uuid" />
   </id>
   <!-- 设置主键不能重复和不能为空的属性. -->
   <property name="name" length="30"unique="true" not-null="true"/>
   <property name="password"/>
   <property name="createTime" type="date" column="create_time"/>
   <property name="expireTime"/>
  </class>
</hibernate-mapping> 

通过User1.hbm.xml映射文件将User1对象转换为关系数据库中的表t_user1。

转换出的结果如下所示:

2 对象关系映射

2.1 多对一关联映射(单向)

例如用户和组的关系就是多对一的关系,多个用户对应一个组。

将实体映射成表,将对应的实体映射成表。对应的属性映射成表字段。

多对一关联映射是在多的一端来维护关联字段,在我们这个例子中也就是在用户一端来维护关系字段。

User.hbm.xml文件。

<hibernate-mapping package="org.hibernate.auction"> 

  <class name="com.bjpowernode.hibernate.User" table="t_user" >
   <id name="id">
     <generator class="native" />
   </id>
   <property name="name"/>
   <many-to-one name="group" column="groupid"cascade="save-update"></many-to-one>
  </class>
</hibernate-mapping> 

Group.hbm.xml文件。

<hibernate-mapping package="org.hibernate.auction"> 

  <class name="com.bjpowernode.hibernate.Group" table="t_group">
   <id name="id">
     <generator class="native" />
   </id>
   <property name="name"/>
  </class>
</hibernate-mapping> 

在这里我们看的代码就看*.hbm.mlx代码,因为对于类之间的关联,在实现时,一个类作为另一个类的私有成员,这一点在学UML建模的时候我们都懂了,在这里主要看的是ORM的M,也就是*.hbm.xml文件。

2.2 一对一关联映射

一对一关联映射在实际生活中是比较常见的,如人与家庭住址的关系,通过人这个对象可以找到他家庭住址相关的内容。

2.2.1 一对一映射(单向主键关联)

单向一对一主键关联,靠的是它们的主键相等,从Person中能看到IdCard,也就是把t_idCard中的主键拿过来当做t_Pseron的主键。

Xml文件中:

<class name="com.bjpowernode.hibernate.Person"table="t_person" >
   <id name="id">
   <!-- 采用foreign生成策略,foreign会取得关联对象的标识 -->
     <generator class="foreign" >
     <!--property指的是关联对象。 -->
      <param name="property">idCard</param>
     </generator>
   </id>
   <property name="name"/>
   <!-- 一对一关联映射,主键关联. -->
   <!--
   one-to-one标签指示hibernate如何加载其关联对象,默认根据主键加载.
   也就是拿到关系字段值,根据对端的主键来加载关联对象.
   constrained="true",表示当前主键(Person的主键)还是一个外键 .
   参照了对端的主键(IdCard的主键),也就是会生成外键约束语句.
   -->
   <one-to-one name="idCard" constrained="true"/>
  </class> 
<hibernate-mapping package="org.hibernate.auction"> 

  <class name="com.bjpowernode.hibernate.IdCard" table="t_idCard" >
   <id name="id">
     <generator class="native" />
   </id>
   <property name="cardNo"/>
  </class>
</hibernate-mapping> 

一对一的关系是通过one-to-one元素定义的。

2.2.2 一对一映射(双向主键关联)

一对一双向主键关联与一对一单向主键关联的区别就是,一对一单向主键关联,在person端能看到idCard,而idCard不能看到Person端。而双向关联就是在idCard端也能看到person,也就是不但在Person.hbm.xml中加上<one-to-one>标签,同时在IdCard.hbm.xml文件中加上<one-to-one>标签。代码如下所示。

<hibernate-mapping package="org.hibernate.auction"> 

  <class name="com.bjpowernode.hibernate.IdCard" table="t_idCard" >
   <id name="id">
     <generator class="native" />
   </id>
   <property name="cardNo"/>
   <one-to-one name="person"/>
  </class>
</hibernate-mapping> 

2.2.3 一对一映射(单向唯一外键关联)

一对一单向唯一外键关联,也就是多对一关联的特例,把多的一端限制为一,就是一对一唯一外键关联。同多对一一样,在一端加入另一端的并采用<many-to-one>标签,通过unique="true",这样来限制了多的一端为一。
先上代码。

IdCard.hbm.xml

<hibernate-mapping package="org.hibernate.auction"> 

  <class name="com.bjpowernode.hibernate.IdCard" table="t_idCard" >
   <id name="id">
     <generator class="native" />
   </id>
   <property name="cardNo"/>
  </class>
</hibernate-mapping> 

Person.hbm.xml

<hibernate-mapping package="org.hibernate.auction"> 

  <class name="com.bjpowernode.hibernate.Person" table="t_person" >
   <id name="id">
   <!-- 采用foreign生成策略,foreign会取得关联对象的标识 -->
     <generator class="native" /> 

   </id>
   <property name="name"/>
   <many-to-one name="idCard" unique="true"></many-to-one> 

  </class>
</hibernate-mapping> 

图如下所示:

在t_pserson端加上一个外键字段idCard,限制idCard的唯一性就是一对一唯一外键关联。

2.2.4 一对一映射(双向唯一外键关联)

一对一唯一外键单向关联我们已经了解了,双向反过来就是在没有的一端加上就可以了。

我们的IdCard.hbm.xml中采用<one-to-one>标签。

<hibernate-mapping package="org.hibernate.auction"> 

  <class name="com.bjpowernode.hibernate.IdCard" table="t_idCard" >
   <id name="id">
     <generator class="native" />
   </id>
   <property name="cardNo"/>
   <one-to-one name="person" property-ref="idCard"></one-to-one>
  </class>
</hibernate-mapping> 

而person.hbm.xml同一对一唯一外键单向关联一样。

<class name="com.bjpowernode.hibernate.Person" table="t_person" >
  <id name="id">
  <!-- 采用foreign生成策略,foreign会取得关联对象的标识 -->
    <generator class="native" /> 

  </id>
  <property name="name"/>
  <many-to-one name="idCard" unique="true"></many-to-one> 

 </class> 

从上述中可以总结出,对于一对一关联映射,主键关联和唯一外键关联单向和双向产生出的表结构是一样的,不同的是在加载的时候不同。也就是一对一双向关联和一对一单向关联的相比,只是改变了一对一关联映射的加载,而没有改变存储。

2.3 一对多关联映射

2.3.1 一对多关联映射(单向)

上面我们介绍了多对一,我们反过来看一对多不就是多对一吗?那还用再进行不同的映射吗?有什么差别吗?一对多和多对一映射原理是一致的,存储是相同的,也就是生成的数据库的表是一样的,他们之间不同的是维护的关系不同。

他们之间不同点是维护的关系不同

  1. 多对一维护的关系是:多指向一的关系,有了此关系,加载多的时候可以将一加载上来。
  2. 一对多维护的关系是:一指向多的关系,有了此关系,在加载一的时候可以将多加载上来。

代码如下所示。

Class.hbm.xml

<class name="com.bjpowernode.hibernate.Classes" table="t_Classes" >
   <id name="id">
     <generator class="native" />
   </id>
   <property name="name"/>
   <set name="students">
   <!--
     <keycolumn="classesid" not-null="true"/>
   -->
     <key column="classesid" />
     <one-to-many class="com.bjpowernode.hibernate.Student"/>
   </set>
  </class> 

Students.hbm.xml

<class name="com.bjpowernode.hibernate.Student" table="t_student" >
   <id name="id">
    <generator class="native" />
   </id>
   <property name="name"/>
 </class>

从班级能看到学生,是班级来维护关系,不是学生来维护关系,学生不知道自己是哪个班,所以在存储学生的时候,班级的代码不知道。为了更新学生是哪个班级的要发出很多update语句来告诉学生是哪个班级的。当我们设置classesid not-null=“true”时,则将无法保存数据,解决办法我们改为双向关联映射。

2.3.2 一对多关联映射(双向)

为了解决一对多单向可能存在的问题,我们采用双向一对多,每一方都能维护对方。

一对多双向关联映射方式:

  1. 在一的一端的集合上采用<key>标签,在多的一端加入一个外键。
  2. 在多的一端采用<many-to-one>的标签

!~注意<key>标签和<many-to-one>标签加入字段保持一致,否则会产生数据混乱。

代码如下所示。

<class name="com.bjpowernode.hibernate.Classes" table="t_Classes" >
   <id name="id">
     <generator class="native" />
   </id>
   <property name="name"/>
   <set name="students" inverse="true">
   <!--
     <keycolumn="classesid" not-null="true"/>
   -->
     <key column="classesid" />
     <one-to-many class="com.bjpowernode.hibernate.Student"/>
   </set>
  </class> 
<class name="com.bjpowernode.hibernate.Student" table="t_student" >
   <id name="id">
     <generator class="native" />
   </id>
   <property name="name"/>
    <many-to-one name="classes"column="classesid"/>
  </class> 

注意:Inverse属性

1、 Inverse中文意思为相反的,反转。在hibernate中inverse可以用在一对多和多对多双向关联上,inverse默认是false,为false的时候表示本端可以维护关系,如果inverse为true,则本端不能维护关系,会交给另一端维护关系,本端失效,所以在一对多关联映射我们通常在多的一端维护关系,让一的一端失效。

2、Inverse是控制方向上的反转,只影响存储。

比较一对多单向和双向映射,从存储结构上看没有什么区别,但是从配置文件上看,一对多双向比一对多单向,一对多双向关联的配置文件中在多的一端的配置文件上存在<many-to-one>相关配置,即保证多对一的映射。

2.4 多对多关联映射

2.4.1 多对多关联映射(单向)

多对多对象关系映射,需要加入一张新表完成基本映射。如下图所示。

代码。

Role.hbm.xml

<class name="com.bjpowernode.hibernate.Role" table="t_role">
   <id name="id">
     <generator class="native" />
   </id>
   <property name="name"/> 

  </class> 

User.hbm.xml

<class name="com.bjpowernode.hibernate.User" table="t_user" >
   <id name="id">
     <generator class="native" />
   </id>
   <property name="name"/> 

   <set name="roles" table="t_user_role">
     <key column="user_id"/>
     <many-to-many class="com.bjpowernode.hibernate.Role" column="role_id"/>
   </set>
  </class> 

2.4.2 多对多关联映射(双向)

双向多对多对象关系映射,是两端都能将对方加载上来,双向都需要加上标签映射。
要注意:

  1. 生成中间表名必须一样
  2. 生成中间表字段必须一样

代码如下所示。

Role.hbm.xml

<class name="com.bjpowernode.hibernate.Role" table="t_role">
   <id name="id">
    <generator class="native" />
   </id>
   <property name="name"/> 

   <set name="users" table="t_user_role">
    <key column="role_id"/>
    <many-to-many class="com.bjpowernode.hibernate.User" column="user_id"/>
   </set>
 </class> 

User.hbm.xml

<class name="com.bjpowernode.hibernate.User"table="t_user" >
   <id name="id">
     <generator class="native" />
   </id>
   <property name="name"/> 

   <set name="roles" table="t_user_role">
     <key column="user_id"/>
     <many-to-many class="com.bjpowernode.hibernate.Role" column="role_id"/>
   </set>
  </class> 

区别:单向多对多和双向多对多存储结构没有任何的区别,但他们的映射文件是有区别的,加载过程是不同的。

 3  关系映射总结

综上所述,可以看出,同一类映射,无论是单向还是双向,他们的存储结构是相同的,之所以映射文件不同,是因为加载时不同(在增删改时)。

无论是多对一、一对多、一对一还是多对一,A对B,A就是主动方,A主动想要了解B的情况,这样把B设置到A端。而双向,也就是A对B,A想了解B的信息,而B也想了解A的信息,那就要同时把A设置到B端了。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • Hibernate实体对象继承的三种方法

    Hibernate实体对象继承的方法 hibernate继承策略总共有三种,一种是共用一张表:一种是每个类一张表,表里面储存子类的信息和父类的信息:还有一种是通过表连接的方式,每个类都有一张表,但是子类对应的表只保存自己的信息,父类对应的表保存父类的信息,它们之间通过子类表和父类表的关联来获取所有的信息. 第一种方式,即共用一张表: @Entity @Inheritance(strategy=InheritanceType.SINGLE_TABLE) @DiscriminatorColumn(n

  • 基于Hibernate中配置文件的学习(分享)

    首先我们看一下hibernate的主配置文件 <!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd"> <hibernate-configuration> <!-- 通常,一个sessi

  • Spring4整合Hibernate5详细步骤

    Spring与Hiberante整合 通过hibernate的学习,我们知道,hibernate主要在hibernate.cfg.xml配置文件中 接下来我们看一下hibernate的一个配置文件 hibernate配置文件 hibernate.cfg.xml <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE hibernate-configuration PUBLIC "-//Hibern

  • Hibernate识别数据库特有字段实例详解

    Hibernate识别数据库特有字段实例详解 前言: Hibernate已经为绝大多数常用的数据库数据类型提供了内置支持,但对于某些数据库的专属字段支持就不够好了. 这些特殊数据类型往往提供了比常规数据类型更好的数据表达能力,更符合我们的业务场景.比如PostgreSQL的Interval类型,可以非常方便的保存一个时间段的数据. 本文以添加Interval类型支持为例,说明为Hibernate添加特有数据类型支持的方法. Hibernate提供了丰富的数据类型支持,但对于部分数据库专有的数据类

  • java中hibernate二级缓存详解

    Hibernate的二级缓存 一.缓存概述 缓存(Cache): 计算机领域非常通用的概念.它介于应用程序和永久性数据存储源(如硬盘上的文件或者数据库)之间,其作用是降低应用程序直接读写永久性数据存储源的频率,从而提高应用的运行性能.缓存中的数据是数据存储源中数据的拷贝.缓存的物理介质通常是内存 hibernate中提供了两个级别的缓存 第一级别的缓存是 Session 级别的缓存,它是属于事务范围的缓存.这一级别的缓存由 hibernate 管理的,一般情况下无需进行干预 第二级别的缓存是 S

  • Spring Boot + Jpa(Hibernate) 架构基本配置详解

    1.基于springboot-1.4.0.RELEASE版本测试 2.springBoot + hibernate + Druid + MySQL + servlet(jsp) 不废话,直接上代码 一.maven的pom文件 <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi=&qu

  • spring+hibernate 两种整合方式配置文件的方法

    之前的文章都是讲解springmvc+spring+mybatis 的整合,而很少有springmvc+spring+hibernate 因为工作的需要,最近在使用hibernate 所以下面我们来看看 spring整合hibernate的配置文件,这里只说spring+hibernate 的配置文件而不说springmvc 因为这些是不用变的. spring整合hibernate 有两种方式 1.注解方式 2.xml方式实现 1.注解方式实现: applicationContext.xml配置

  • Spring Hibernate实现分页功能

    本实例采用Spring+Hibernate实现简单的分页功能,供大家参考,具体内容如下 最关键的是运用Hibernate的query里面的两个方法: query.setFirstResult((p.getPage()-1)*p.getRows()); 指定从那个对象开始查询,参数的索引位置是从0开始的. query.setMaxResults(p.getRows()); 分页时,一次最多产寻的对象数 主要实现类: package com.paging; import java.util.List

  • Hibernate映射之基本类映射和对象关系映射详解

    回想一些我们在没有学习ssh的时候,我们建立数据库的表时,首先是数据库建模E-R图,然后再通过实体模型来建立关系模型,再建立相应的表.实体间存在三种关系,一对一,一对多(或者说多对一),多对多.而如今我们要根据类来映射相应的表,那只能是通过类与类之间的关系加上映射文件来映射数据库的表.我们学习UML建模,类与类之间存在五种关系,继承,实现,关联,依赖,聚合/组合,在hibernate中实体类之间的关系也是如此,对于不同的关系对应的代码实现我们已经很熟悉了,所以对于实体类是复习的知识. Hiber

  • hibernate中的对象关系映射

    Hibernate的本质就是对象关系映射(ObjectRelational Mapping),ORM实现了将对象数据保存到数据库中,以前我们对关系表进行操作,执行增删改查等任务,现在我们不再对关系表进行操作,而是直接对对象操作.hibernate中的ORM映射文件通常以.hbm.xml作为后缀.使用这个映射文件不仅易读,而且可以手工修改,也可以通过一些工具来生成映射文档.下面将对hibernate中的映射进行介绍. Hibernate映射分类,如下图所示. 1 基本类映射 根据实体类创建相应的表

  • 详解PHP的Laravel框架中Eloquent对象关系映射使用

    零.什么是 Eloquent Eloquent 是 Laravel 的 'ORM',即 'Object Relational Mapping',对象关系映射.ORM 的出现是为了帮我们把对数据库的操作变得更加地方便. Eloquent 让一个 'Model类' 对应一张数据库表,并且在底层封装了很多 'function',可以让 Model 类非常方便地调用. 来看一段如下代码: <?php class Article extends \Eloquent { protected $fillabl

  • Django 对象关系映射(ORM)源码详解

    前言 从前面已经知道, 一个 request 的到来和一个对应 response 的返回的流程, 数据处理和数据库离不开. 我们也经常在 views.py 的函数定义中与数据库打交道. django ORM 源代码组织结构 对于数据库, django 有自己的一套 ORM(对象关系映射), 或许其他的框架可以随意更换 ORM, 但 django 不建议这么做. 因为 django 内置有很多的 model, 这些 model 无疑是用 django 内置 ORM 实现的, 如果更换后, 内置的

  • JavaScript 中有关数组对象的方法(详解)

    JS 处理数组多种方法 js 中的数据类型分为两大类:原始类型和对象类型. 原始类型包括:数值.字符串.布尔值.null.undefined 对象类型包括:对象即是属性的集合,当然这里又两个特殊的对象----函数(js中的一等对象).数组(键值的有序集合). 数组元素的添加 arrayObj.push([item1 [item2 [. . . [itemN ]]]]); 将一个或多个新元素添加到数组结尾,并返回数组新长度 arrayObj.unshift([item1 [item2 [. . .

  • JavaScript中子对象访问父对象的方式详解

    在传统面向对象的编程语言里,都会提供一种子类访问父类的特殊语法,引文我们在实现子类方法往往需要父类方法的额外辅助.在这种情况下,子类通常会调用父类中的同名方法,最终以便完成工作. javascript虽然没有类似上述的特殊语法,但我们可以造一个啊! function her(){}; her.prototype.name = 'Anna'; her.prototype.toString = function(){ var const = this.constructor; return cons

  • C++ 中引用和指针的关系实例详解

    C++ 中引用和指针的关系实例详解 1.引用在定义时必须初始化,指针没有要求 int &rNum; //未初始化不能通过编译 int *pNum; //可以 2. 一旦一个引用被初始化为指向一个对象,就不能再指向 其他对象,而指针可以在任何时候指向任何一个同类型对象 int iNum = 10; int iNum2 = 20; int &rNum = iNum; &rNum = iNum2; //不能通过 3. 没有NULL引用,但有NULL指针. int *pNum = NULL

  • PHP laravel中的多对多关系实例详解

    数据表之间是纵横交叉.相互关联的,laravel的一对一,一对多比较好理解,官网介绍滴很详细了,在此我就不赘述啦,重点我记下多对多的关系 一种常见的关联关系是多对多,即表A的某条记录通过中间表C与表B的多条记录关联,反之亦然.比如一个用户有多种角色,反之一个角色对应多个用户. 为了测试该关联关系,我们沿用官网的用户角色示例: 需要三张数据表:users.roles 和 role_user,role_user 表按照关联模型名的字母顺序命名(这里role_user是中间表),并且包含 user_i

  • Hibernate迫切连接和普通连接的区别实例详解

    Hibernate 迫切连接和普通连接的区别 相关的介绍和解释在代码中已注释,大家可以参考. package com.baidu.test; import java.util.ArrayList; import java.util.LinkedHashSet; import java.util.List; import org.hibernate.Query; import org.hibernate.Session; import org.hibernate.SessionFactory; i

  • Android Handle原理(Looper,Handler和Message三者关系案例详解

    介绍 前面的内容对Handler做了介绍,也讲解了如何使用handler,但是我们并不知道他的实现原理.本文从源码的角度来分析如何实现的. 首先我们得知道Handler,Looper,Message Queue三者之间的关系 - Handler封装了消息的发送,也负责接收消.内部会跟Looper关联. - Looper 消息封装的载,内部包含了MessageQueue,负责从MessageQueue取出消息,然后交给Handler处理 - MessageQueue 就是一个消息队列,负责存储消息

随机推荐