Java的Hibernate框架中的基本映射用法讲解

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

映射是通过XML来定义的,使用Hibernate创建的session来管理,最后由session使用JTA把更改提交到数据库中。session可以理解为持久化管理器,管理持久层中的对象,它是由sessionFactory创建的。使用Hibernate编程时首先要连接数据库,所以首先要去查看xml中有关数据库连接的配置,根据文档的配置创建sessionFactory(可以理解为数据库镜像),再由sessionFactory创建一个session,最后由session统一将更改提交到数据库,这才完成了一部所有的操作。

使用过程
1.创建映射文件,映射文件以.hbm.xml为后缀名,标明它是Hibernate的映射文件;
2.在映射文件中注册实体类,并将实体类的属性添加到映射类中,在添加属性时要指定两种值分别是id和property,id指明它是一个实体的唯一标示,property指明它是表的字段列;
3.提交修改,同步数据。
Note:开发过xml数据转到数据库的开发人员很快就能理解这种映射其实是一种批量更新、批量创建的过程,映射也不例外,Hibernate规定了一套映射标准,按照标准就能够实现转换,它的内部实现还是死的,所以它只是相对的灵活易用。

一个简单的实体类映射过程:
1. 实体类User1的属性代码:

package com.hibernate; 

import java.util.Date; 

public class User1 {
 private String id;
 private String name;
 private String password;
 private Date createTime;
 private Date expireTime;
 public String getId() {
  return id;
 }
 public String getName() {
  return name;
 }
 public void setName(String name) {
  this.name = name;
 }
 public String getPassword() {
  return password;
 }
 public void setPassword(String password) {
  this.password = password;
 }
 public Date getCreateTime() {
  return createTime;
 }
 public void setCreateTime(Date createTime) {
  this.createTime = createTime;
 }
 public Date getExpireTime() {
  return expireTime;
 }
 public void setExpireTime(Date expireTime) {
  this.expireTime = expireTime;
 } 

}

2. User1.java的映射文件User1.hbm.xml的内部代码实现:
基础数据库中能够设置的在Hibernate中同样提供了设置的方法,可以使用标签属性来设置具体的映射关系。
类-->表使用class标签,常用属性:
(1)name:映射实体类,它的值需要设置为需要转化成表的实体类的名称,在同步时会根据该属性查找相应的实体类。
(2)table:映射数据库表的名称,如果要映射的表的名称和实体类名称不相同,使用该属性来指定映射的表,如果不存在的话会根据该属性值创建一个表。
 查看上图中配置生成的表结构,如下图:

其中的表名更改为了t_user1;id字段更名为user_id,字段长度为32位;createTime属性,映射为数据库字段create_time,并修改为date类型。
属性-->字段使用id或property标签,常用属性:
(1)name:功能类似于class标签的name,值定实体类的映射属性名;
(2)column:类似于实体类class标签的table,指定映射表的列名称,如果不存在将会创建;
(3)type:指定映射到数据库中字段的数据类型,根据需要查看文档即可;
(4)generator,它是可选的,用来为一个持久类生成唯一的标识。

<id name="id" type="long" column="cat_id">
  <generator class="org.hibernate.id.TableHiLoGenerator">
    <param name="table">uid_table</param>
    <param name="column">next_hi_value_column</param>
  </generator>
</id>

所有的生成器都实现org.hibernate.id.IdentifierGenerator接口。 这是一个非常简单的接口;某些应用程序可以选择提供他们自己特定的实现。当然, Hibernate提供了很多内置的实现。下面介绍常用的几种:
(1)identity:返回的标识符是long, short 或者int类型的。类似于数据库的自增字段。
(2)sequence:在DB2,PostgreSQL, Oracle, SAP DB, McKoi中使用序列(sequence), 而在Interbase中使用生成器(generator)。返回的标识符是long, short或者 int类型的。在整个数据库中自增,而不是单个的表中自增,需要指定单个的表中自增需要添加属性。
(3)uuid:用一个128-bit的UUID算法生成字符串类型的标识符, 这在一个网络中是唯一的(使用了IP地址)。UUID被编码为一个32位16进制数字的字符串。类似于.NET生成的序列号。
(4)native:根据底层数据库的能力选择identity, sequence 或者hilo中的一个。灵活的方式,会根据使用的数据库来确定使用的标识类型,MySQL会选择identity,Oracle选择sequence。
(5)assigned:手动为实体类制定一个标识id。这是 <generator>元素没有指定时的默认生成策略。
(6)foreign:使用另外一个相关联的对象的标识符。通常和<one-to-one>联合起来使用。
开发人员往往习惯了手动配置的方法根据文档的说明来编写配置属性,这样做很原始,初学者建议采用手动配置的方法,有助于思考。另外还有很多第三方工具,通过可视化的方法来配置然后生成xml配置文档,提高了开发效率,类似的工具如:XDoclet、Middlegen和AndorMDA。
 
关联映射之多对一
上面讨论了Hibernate的基本映射,一个实体类对应着一张表,在相应的Hibernate Mapping文件中使用<class>标签映射。并且实体类中的普通属性对应着表字段,使用<property>标签映射。另外在构造实体类时应注意:在实体类中应实现无参的默认的构造函数,提供一个标示,建议不要使用final修饰实体类,为实体类生成getter和setter方法,最后介绍了几种主要的主键生成策略,接下来讨论多对一映射。

这种多对一关联映射反应到对象模型中它是一种聚合关系,User是group的一部分,group中存在User,它们两个的生命周期是不相同的,可反应为下图:

那么这种多对一关系映射在Hibernate中是如何设置的呢?下面将会介绍两种方法,使用<many-to-one>标签直接映射,或者使用<many-to-one>的cascade级联修改表。
 1、Many-to-one直接映射
从字面意思上就能够理解,它是指多对一的关系,many指的是多的一端,one指的是少的一端,在使用时往往在多的一端的hbm中使用该标签,并将<many-to-one>的name属性设置为该映射文件对应的类中的one一端的属性,如:<many-to-one name="group" column="groupid"></many-to-one>,该标签添加在了User.hbm.xml中,它对应many;标签中的name值为group对映射one,并且在User.java中会有一个名为group的属性。接下来看下具体实现实现的代码类。
(1)User.java类代码,其中有一个名为group的属性,它将会作为<many-to-one>的one一端的name值。

public class User {
 private String name;
 public String GetName(){
  return name;
 }
 public void SetName(String name){
  this.name=name;
 } 

 private Group group;
 public Group GetGroup(){
  return group;
 }
 public void SetGroup(Group group){
  this.group=group;
 }
}

(2)User.hbm.xml中的<many-to-one>,name的值为User.java中one端的属性值,它会在数据库中生成一个新列,可以将该新列理解为User表的外键。

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!-- Generated 2014-5-14 23:39:25 by Hibernate Tools 3.4.0.CR1 -->
<hibernate-mapping>
 <class name="com.hibernate.User" table="USER">
  <id name="id" type="java.lang.Long">
   <column name="ID" />
   <generator class="assigned" />
  </id> 

  <!-- name的值group为User.java中的一个对应的one中的一个属性,它会自动在表中生成一列,所以使用column对列进行了重命名 -->
  <many-to-one name="group" column="groupid"></many-to-one> 

 </class>
</hibernate-mapping> 

(3)测试上面的映射关系,向表中写入两个User对象分别为user1和user2,命名为张三和李四,使用session保存对象,向数据库中写入数据,代码如下:

public void testSave1(){ 

  Session session=null;
  try{
   session=GetSession.getSession();
   session.beginTransaction(); 

   Group group=new Group();
   group.SetName("动力节点"); 

   User user1=new User();
   user1.SetName("张三");
   user1.SetGroup(group); 

   User user2=new User();
   user2.SetName("李四");
   user2.SetGroup(group); 

   session.save(user1);
   session.save(user2); 

   //会报TransientObjectException错误
   //在清理缓存时发生错误TransientObjectException
   //因为Group为Transient状态,没有被Session,在数据库中没有匹配的数据
   //而User为Persistent状态,在清理缓存时Hibernate在缓存中无法找到Group对象
   //揭露:Persistent状态的对象不能引用Transient状态的对象
   //该问题在testSave2方法中更改
   session.getTransaction().commit();
  }catch(Exception e){ 

   e.printStackTrace();
   session.getTransaction().rollback();
  }finally{
   GetSession.CloseSession(session);
  }
 }

但是使用上面的代码在执行写入时会报错TransientObjectException,这是因为在保存User对象时它会按照<many-to-one>中添加的group去内存中查找group对象,但是上面的代码中group对象一直都是在Transient状态中,并没有被session管理,也就是说查找不到session对象,而User对象进入了Persistent状态,于是会报此错误。正确的代码如下:

public void testSave2(){ 

 Session session=null;
 try{
  session=GetSession.getSession();
  session.beginTransaction(); 

  Group group=new Group();
  group.SetName("动力节点");
  session.save(group);  //此处将group对象设置为Persistent对象 

  User user1=new User();
  user1.SetName("张三");
  user1.SetGroup(group); 

  User user2=new User();
  user2.SetName("李四");
  user2.SetGroup(group); 

  session.save(user1);
  session.save(user2); 

  //可以正确的保存数据
  //因为Group和User都是Persistent状态的对象
  //所以在Hibernate清理缓存时在session中可以找到关联对象
  session.getTransaction().commit();
 }catch(Exception e){ 

  e.printStackTrace();
  session.getTransaction().rollback();
 }finally{
  GetSession.CloseSession(session);
 }
}

2、级联映射
除了上面所说的将group对象和user对象都转化到Persistent对象外,还可以使用cascade级联映射属性,在<many-to-one>属性中添加cascade属性,并复制为save-update,在group对象并非为Persistent状态时即可写入数据库。这样只需要将两个user对象的Group属性设置为同一个group对象即可实现多对一的映射关系,此时User.hbm.xml中对应的内容为如下代码:

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!-- Generated 2014-5-14 23:39:25 by Hibernate Tools 3.4.0.CR1 -->
<hibernate-mapping>
 <class name="com.hibernate.User" table="USER">
  <id name="id" type="java.lang.Long">
   <column name="ID" />
   <generator class="assigned" />
  </id> 

  <!-- 级联修改表 -->
  <many-to-one name="group" column="groupid" cascade="save-update"></many-to-one> 

 </class>
</hibernate-mapping>

Note:cascade设置为save-update后即可实现向数据库中级联修改、添加和删除,但是具体的级联查询操作却不可以。
对应的测试配置文件的方法为如下代码:

//级联cascade
public void testSave3(){ 

 Session session=null;
 try{
  session=GetSession.getSession();
  session.beginTransaction(); 

  Group group=new Group();
  group.SetName("动力节点"); 

  User user1=new User();
  user1.SetName("张三");
  user1.SetGroup(group); 

  User user2=new User();
  user2.SetName("李四");
  user2.SetGroup(group); 

  session.save(user1);
  session.save(user2); 

  //没有抛出TransientObjectException异常
  //因为使用了级联
  //Hibernate会首先保存User的关联对象Group
  //Group和User就都是Persistent状态的对象了
  session.getTransaction().commit();
 }catch(Exception e){
  e.printStackTrace();
  session.getTransaction().rollback();
 }finally{
  GetSession.CloseSession(session);
 }
}

3、对比升华
 两种方法同样实现了多对一的映射方法,结果上是相同的,但在实现上很不相同。无论是第一种还是第二种采用的都是<many-to-one>在many一端的映射文件中添加该标签,并将标签的name属性赋值为该映射文件注册的类中的one一端的属性值,这样就完成了多对一的基本映射,这是相同点。不同点是直接映射关系没有采用Hibernate字段的属性,这样在实现上较灵活,不但支持增删改,而且可以查询;第二种的cascade级联修改则采用了Hibernate提供的方法,此种方法只支持增删改,并不支持查询。

(0)

相关推荐

  • 深入解析Java的Hibernate框架中的一对一关联映射

    作为一个ORM框架,hibernate肯定也需要满足我们实现表与表之间进行关联的需要.hibernate在关联方法的实现很简单.下面我们先来看看一对一的做法:  不多说了,我们直接上代码:  两个实体类,TUser和TPassport: public class TUser implements Serializable{ private static final long serialVersionUID = 1L; private int id; private int age; priva

  • 详解Java的Hibernate框架中的set映射集与SortedSet映射

    Set 集合Set是一个java集合不包含任何重复的元素.更正式地说,Set不包含任何元素对e1和e2,使得e1.equals(e2),和至多一个空元素.所以被添加到一组对象必须实现equals()和hashCode()方法,使Java可以判断任何两个元素/对象是否是相同的. 集被映射到与映射表中<set>元素,并在java.util.HashSet中初始化.可以使用Set集合在类时,有一个集合中不需要重复的元素. 定义RDBMS表: 考虑一个情况下,我们需要我们的员工记录存储在EMPLOYE

  • hibernate中的对象关系映射

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

  • Java的Hibernate框架中复合主键映射的创建和使用教程

    复合主键映射需要在映射配置文件中使用<composite-id>标签,该标签是指将一个类指定为相应的复合主键,它的name属性需要指定类文件中定义的属性值,并在该标签中添加<key-property>子标签. Note:想要使用复合映射必须要将复合主键放到一个类中,也就是讲复合主键属性和其它属性分到两个类中,并将复合主键的类实现接口Serializable,该接口隶属于java.io. 复合主键的映射关系的主键是由多个列复合而成的,对应到数据表中相当的简单,如下图: 1.类文件 这

  • 举例讲解Java的Hibernate框架中的多对一和一对多映射

    多对一(Many-to-One)映射 多对一(many-to-one)关联是最常见的关联关系,其中一个对象可以与多个对象相关联.例如,一个相同的地址对象可以与多个雇员的对象相关联. 定义RDBMS表: 考虑一个情况,我们需要员工记录存储在EMPLOYEE表,将有以下结构: create table EMPLOYEE ( id INT NOT NULL auto_increment, first_name VARCHAR(20) default NULL, last_name VARCHAR(20

  • 解析Java的Hibernate框架中的持久化类和映射文件

    持久化类 Hibernate的整个概念是采取从Java类属性的值,并将持久到数据库表.一个映射文件Hibernate的帮助确定如何从拉动类的值,并将它们映射与表和相关的域. 其对象或实例将存储在数据库表中的Java类在Hibernate中称为持久化类. Hibernate的效果最好,如果这些类遵循一些简单的规则,也称为普通Java对象(POJO)编程模型.有下列持久化类的主要规则,但是,这些规则并不是必需的. 将所有的持久化Java类需要一个默认的构造函数. 所有类应该包含为了让容易识别对象内H

  • 详解Java的Hibernate框架中的List映射表与Bag映射

    List映射表 List列表是一个java集合存储在序列中的元素,并允许重复的元素.此接口的用户可以精确地控制,其中列表中的每个元素插入.用户可以通过他们的整数索引访问元素,并搜索列表中的元素.更正式地说,列表通常允许对元素e1和e2,使得e1.equals(e2),它们通常允许多个null元素,如果他们允许的null元素. List列表被映射在该映射表中的<list>元素,并将java.util.ArrayList中初始化. 定义RDBMS表: 考虑一个情况,需要员工记录存储在EMPLOYE

  • Java的Hibernate框架中一对多的单向和双向关联映射

    一.一对多单向关联映射 一对多关系的对象模型在日常生活中也经常看到,就拿学生和班级来说,一个班级里有多个学生,所以班级和学生的关系是一对多的关系,映射到对象模型中,如下图: 对象模型说明了这种一对多的关系是由一的一端来维护的,那么映射成关系模型就是一个班级字段下面会有多个学生,这样就形成了一对多的关系,通过班级能够查询获得学生信息,对应的关系模型如下图: 1.基本配置 有了对象模型接下来就让它们映射为对应的关系代码,在进行关系映射时需要在一的一端添加<one-to-many>标签,另外还需要在

  • Java的Hibernate框架中的基本映射用法讲解

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

  • Java的Hibernate框架中的组合映射学习教程

    一.组合映射 组合是关联关系的一种特殊情况,是关联关系耦合度最高的一种关系,组合的主对象和子对象拥有相同的生命周期,主对像消亡的话子对象也会消亡.这里使用雇主和用户作为示例,用户和雇主都拥有联系方式属性,如果这里站在对象角度思考的话,常常会把对象模型绘制成为组合的方式,抽象出来一个共同的联系方式类,然后两种人分别包含相应的联系方式对象即可,向应的对象模型时它的对象示例如下图所示: 组合对象模型在生成相应的关系模型后会把对应的子类包含到主表中,所以对应的表结构会将相应的属性生成到对应的表中,相应的

  • Java的Hibernate框架中的继承映射学习教程

    一.继承映射 继承是面向对象很重要的特性,它实现了代码的服用,在关系模型中同样也有继承关系,这种继承关系其实可以看做是一种枚举关系,一种类型中可以枚举出很多子类型,这些子类型和父对象形成了继承关系,能够对其进行枚举的大部分都可以看做是一种继承映射,所以这种枚举关系可以看做是继承映射,例如动物就是一种抽象类,它是其它动物猪.猫等的父类,它们之间就是一种继承关系,如下图: 这种继承映射在转化为关系模型后会生成一张表,那么这张表是如何区分这两种类型的呢?用的是关系字段,需要在表中添加类型字段,使用关键

  • Java的Hibernate框架中集合类数据结构的映射编写教程

    一.集合映射 1.集合小介 集合映射也是基本的映射,但在开发过程中不会经常用到,所以不需要深刻了解,只需要理解基本的使用方法即可,等在开发过程中遇到了这种问题时能够查询到解决方法就可以了.对应集合映射它其实是指将java中的集合映射到对应的表中,是一种集合对象的映射,在java中有四种类型的集合,分别是Set.Map.List还有普通的数组,它们之间有很大的区别: (1)Set,不可以有重复的对象,对象是无序的: (2)List,可以与重复的对象,对象之间有顺序: (3)Map,它是键值成对出现

  • 深入解析Java的Hibernate框架中的持久对象

    一.持久对象生命周期 应用程序在使用Hibernate框架后,创建的持久对象会经历一整套生命周期来完成数据库的操作,其中主要的三个状态分别是瞬态(Transient).持久化(Persistent).脱管(detached).这三种状态的转换是能够在应用程序中控制的,如下图: 为了能清楚的了解这几种状态,这里使用一个实例来查看下这几种状态下对象的不同,下面状态内的代码,具体步骤如下: (1)创建Hibernate_session程序集,并添加像相应的jar包: (2)配置Hibernate,添加

  • Java的Hibernate框架中的双向主键关联与双向外键关联

    一.双向主键关联 双向的主键关联其实是单向一对一主键关联的一种特殊情况,只不过要在关联对象的两端的映射文件中都要进行<one-to-one>的配置,另外还要在主映射的主键一端采用foreign外键关联属性. 这里同样使用Person和IdCard来讨论,一个人对应着一个唯一的身份证,而且一个身份证也唯一映射着一个人,所以这就产生了双向的关联关系,Person的主键同样也是IdCard的主键,分别是主键的同时也是外键,这种关联关系成为双向一对一映射,表现到关系模型中可如下图: 图中的两个表采用了

  • Java的Hibernate框架中用于操作数据库的HQL语句讲解

    上次我们一起学习了用Criteria进行相关的操作,但由于Criteria并不是Hibernate官方推荐的查询方式,我们也并不多用.现在我们来看一下官方推荐的HQL,一起学习一下它的强大.  说是HQL,也就是Hibernate查询语句,和SQL有什么区别呢?一个字母的区别,哈哈.  当然不是这样,HQL和SQL的区别在于思想的不同,HQL是用面向对象的方向进行查询,而SQL则是对数据库二维表进行查询,这里包含的是思想的不同.HQL实际上也是SQL,它由Hibernate帮我们在内部进行转换,

随机推荐