html5中文学习网

您的位置: 首页 > 网络编程 > java教程 » 正文

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

[ ] 已经帮助:人解决问题

一、继承映射gQ3HTML5中文学习网 - HTML5先行者学习网
继承是面向对象很重要的特性,它实现了代码的服用,在关系模型中同样也有继承关系,这种继承关系其实可以看做是一种枚举关系,一种类型中可以枚举出很多子类型,这些子类型和父对象形成了继承关系,能够对其进行枚举的大部分都可以看做是一种继承映射,所以这种枚举关系可以看做是继承映射,例如动物就是一种抽象类,它是其它动物猪、猫等的父类,它们之间就是一种继承关系,如下图:gQ3HTML5中文学习网 - HTML5先行者学习网
gQ3HTML5中文学习网 - HTML5先行者学习网

201678100006100.png (335×264)gQ3HTML5中文学习网 - HTML5先行者学习网

这种继承映射在转化为关系模型后会生成一张表,那么这张表是如何区分这两种类型的呢?用的是关系字段,需要在表中添加类型字段,使用关键字来标明对象的类型。所以上图中的对象模型对应的表结构如下:gQ3HTML5中文学习网 - HTML5先行者学习网
gQ3HTML5中文学习网 - HTML5先行者学习网

201678100040571.png (669×83)gQ3HTML5中文学习网 - HTML5先行者学习网

在生成表结构时,需要添加对应的字段类型,所以需要在映射文件中添加对应的映射鉴别器,这里就需要使用discriminator-value属性。gQ3HTML5中文学习网 - HTML5先行者学习网
1.类文件gQ3HTML5中文学习网 - HTML5先行者学习网
类文件中没有需要注意的地方,在编写时注意之间的继承关系即可。gQ3HTML5中文学习网 - HTML5先行者学习网
清单一:Animal类代码,只需要添加基本的属性。gQ3HTML5中文学习网 - HTML5先行者学习网
gQ3HTML5中文学习网 - HTML5先行者学习网

package com.src.hibernate;  public class Animal {   //id号  private int id;  public int getId() {  return id;  }  public void setId(int id) {  this.id = id;  }   //名称  private String name;  public String getName() {  return name;  }  public void setName(String name) {  this.name = name;  }   //性别  private boolean sex;  public boolean isSex() {  return sex;  }  public void setSex(boolean sex) {  this.sex = sex;  } } 

清单二:Bird和Pig类,添加基本的属性,并继承Animal类。gQ3HTML5中文学习网 - HTML5先行者学习网

package com.src.hibernate; public class Bird extends Animal {   //高度  private int height;  public int getHeight() {  return height;  }  public void setHeight(int height) {  this.height = height;  }  }  package com.src.hibernate; public class Pig extends Animal {   //重量  private int weight;  public int getWeight() {  return weight;  }  public void setWeight(int weight) {  this.weight = weight;  } } 

2.映射文件gQ3HTML5中文学习网 - HTML5先行者学习网
映射文件中需要添加对应的映射,该模型中只需要添加一个映射文件,因为只生成一张表,在映射文件中添加对应的子类映射,使用<subclass>标签,标签中添加鉴别器discriminator-value,该鉴别器属性指明了在数据库中写入数据时指示写入的是何种类型,如下:gQ3HTML5中文学习网 - HTML5先行者学习网

<?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC  "-//Hibernate/Hibernate Mapping DTD 3.0//EN"  "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> <hibernate-mapping>  <class name="com.src.hibernate.Animal" table="t_animal">  <id name="id">  <generator class="native"/>  </id>  <!-- 加入鉴别标签,且必须放在id后面 -->  <discriminator column="type" />  <property name="name"/>  <property name="sex" type="boolean"/>   <subclass name="com.src.hibernate.Pig" discriminator-value="P">  <property name="weight"/>  </subclass>  <subclass name="com.src.hibernate.Bird" discriminator-value="B">  <property name="height"/>  </subclass>  </class>  </hibernate-mapping> 

3.分析结果gQ3HTML5中文学习网 - HTML5先行者学习网
生成的MySQL数据库表中不仅会添加Animal的基本属性,而且会添加Pig和Bird的属性,因为在映射文件中使用<subclass>写出了所添加的属性,另外还添加了相应的鉴别器属性,所以在数据库中会添加对应的鉴别列,生成的表结构如下图:gQ3HTML5中文学习网 - HTML5先行者学习网
gQ3HTML5中文学习网 - HTML5先行者学习网

201678100102347.png (618×220)gQ3HTML5中文学习网 - HTML5先行者学习网

gQ3HTML5中文学习网 - HTML5先行者学习网

二、数据操作gQ3HTML5中文学习网 - HTML5先行者学习网

1.写入数据gQ3HTML5中文学习网 - HTML5先行者学习网
在进行数据读取和写入操作时需要注意类中的操作使用了gQ3HTML5中文学习网 - HTML5先行者学习网

public void testSave(){  Session session=null;  try{  //创建session对象  session=HibernateUtils.getSession();  //开启事务  session.beginTransaction();   Pig pig=new Pig();  pig.setName("小猪猪");  pig.setSex(true);  pig.setWeight(200);  session.save(pig);   Bird bird=new Bird();  bird.setName("xiaoniaoniao");  bird.setSex(true);  bird.setHeight(100);  session.save(bird);   session.getTransaction().commit();  }catch(Exception e){  e.printStackTrace();  session.getTransaction().rollback();  }finally{  HibernateUtils.closeSession(session);  }  } 

2.多态查询--get和hqlgQ3HTML5中文学习网 - HTML5先行者学习网

基本的查询方法,只需要使用load和get方法即可,这里重点讨论多态查询。多态查询是指Hibernate在加载对象时能够采用instanceof鉴别出其真正的类型的对象即可为多态查询。gQ3HTML5中文学习网 - HTML5先行者学习网
Note:多态查询不支持延迟加载,也就是说如果使用load方法,需要在映射文件中将延迟加载设置为false。gQ3HTML5中文学习网 - HTML5先行者学习网

3.load延迟加载gQ3HTML5中文学习网 - HTML5先行者学习网
load支持延迟加载,在加载对象时其实生成的是对象的代理,所以在使用多态查询时需要在映射文件中将延迟加载设置为false,如下:gQ3HTML5中文学习网 - HTML5先行者学习网

<?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC  "-//Hibernate/Hibernate Mapping DTD 3.0//EN"  "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> <hibernate-mapping>  <class name="com.src.hibernate.Animal" table="t_animal" lazy="false">  <id name="id">  <generator class="native"/>  </id>  <!-- 加入鉴别标签,且必须放在id后面 -->  <discriminator column="type" />  <property name="name"/>  <property name="sex" type="boolean"/>   <subclass name="com.src.hibernate.Pig" discriminator-value="P">  <property name="weight"/>  </subclass>  <subclass name="com.src.hibernate.Bird" discriminator-value="B">  <property name="height"/>  </subclass>  </class> </hibernate-mapping> 

load加载方法,使用load加载该示例中支持多态查询,在配置文件中将延迟加载设置为false,所以这里使用load方法能够加载获得相应的对象类。gQ3HTML5中文学习网 - HTML5先行者学习网

public void testLoad(){  Session session=null;  try{  session=HibernateUtils.getSession();  session.beginTransaction();   Animal ani=(Animal)session.load(Animal.class,1);  System.out.println(ani.getName());  //因为load默认支持lazy,所以我们看到的是Animal的代理  //所以采用了instanceof无法鉴别出真正的类型Pig  //所以load在此情况下是不支持多态查询的  if(ani instanceof Pig){  System.out.println("我是小猪猪!");  }else{  System.out.println("我不是小猪猪!");  }  session.getTransaction().commit();  }catch(Exception e){  e.printStackTrace();  session.getTransaction().rollback();  }finally{  HibernateUtils.closeSession(session);  } } 

4.hql查询gQ3HTML5中文学习网 - HTML5先行者学习网
hql支持多态查询,这主要由于查询出的是一个真正的对象,并不会返回一个代理,所以hql支持多态查询,另外在查询时需要注意查询语句中不要使用表名,而是要使用类名称,Hibernate会根据类名称将其映射为对应的表名称,如下:gQ3HTML5中文学习网 - HTML5先行者学习网

public void testLoad5(){  Session session=null;  try{  session=HibernateUtils.getSession();  session.beginTransaction();   List<Animal> list=session.createQuery("from Animal").list();  for(Iterator iter=list.iterator();iter.hasNext();){  Animal a=(Animal)iter.next();  if(a instanceof Pig){  System.out.println("我是小猪猪!");  }else{  System.out.println("我不是小猪猪!");  }  }  session.getTransaction().commit();  }catch(Exception e){  e.printStackTrace();  session.getTransaction().rollback();  }finally{  HibernateUtils.closeSession(session);  } } 

查询结果:gQ3HTML5中文学习网 - HTML5先行者学习网

Hibernate: select animal0_.id as id0_, animal0_.name as name0_, animal0_.sex as sex0_, animal0_.weight as weight0_, animal0_.height as height0_, animal0_.type as type0_ from t_animal animal0_ 我是小猪猪! 我不是小猪猪! 我是小猪猪! 我不是小猪猪! 

三、继承映射三种策略gQ3HTML5中文学习网 - HTML5先行者学习网
1. 每个类分层结构一张表(Table per class hierarchy)
gQ3HTML5中文学习网 - HTML5先行者学习网

假设我们有接口Payment和它的几个实现类: CreditCardPayment, CashPayment, 和ChequePayment。则“每个类分层结构一张表”(Table per class hierarchy)的映射代码如下所示:gQ3HTML5中文学习网 - HTML5先行者学习网

<class name="Payment" table="PAYMENT">  <id name="id" type="long" column="PAYMENT_ID">  <generator class="native"/>  </id>  <discriminator column="PAYMENT_TYPE" type="string"/>  <property name="amount" column="AMOUNT"/>  ...  <subclass name="CreditCardPayment" discriminator-value="CREDIT">  <property name="creditCardType" column="CCTYPE"/>  ...  </subclass>  <subclass name="CashPayment" discriminator-value="CASH">  ...  </subclass>  <subclass name="ChequePayment" discriminator-value="CHEQUE">  ...  </subclass> </class> 

采用这种策略只需要一张表即可。它有一个很大的限制:要求那些由子类定义的字段, 如CCTYPE,不能有非空(NOT NULL)约束。gQ3HTML5中文学习网 - HTML5先行者学习网

2. 每个子类一张表(Table per subclass)gQ3HTML5中文学习网 - HTML5先行者学习网

对于上例中的几个类而言,采用“每个子类一张表”的映射策略,代码如下所示:gQ3HTML5中文学习网 - HTML5先行者学习网

<class name="Payment" table="PAYMENT">  <id name="id" type="long" column="PAYMENT_ID">  <generator class="native"/>  </id>  <property name="amount" column="AMOUNT"/>  ...  <joined-subclass name="CreditCardPayment" table="CREDIT_PAYMENT">  <key column="PAYMENT_ID"/>  ...  </joined-subclass>  <joined-subclass name="CashPayment" table="CASH_PAYMENT">  <key column="PAYMENT_ID"/>  <property name="creditCardType" column="CCTYPE"/>  ...  </joined-subclass>  <joined-subclass name="ChequePayment" table="CHEQUE_PAYMENT">  <key column="PAYMENT_ID"/>  ...  </joined-subclass> </class> 

需要四张表。三个子类表通过主键关联到超类表(因而关系模型实际上是一对一关联)。gQ3HTML5中文学习网 - HTML5先行者学习网

3. 每个子类一张表(Table per subclass),使用辨别标志(Discriminator)gQ3HTML5中文学习网 - HTML5先行者学习网

注意,对“每个子类一张表”的映射策略,Hibernate的实现不需要辨别字段,而其他 的对象/关系映射工具使用了一种不同于Hibernate的实现方法,该方法要求在超类 表中有一个类型辨别字段(type discriminator column)。Hibernate采用的方法更 难实现,但从关系(数据库)这点上来看,按理说它更正确。若你愿意使用带有辨别字 段的“每个子类一张表”的策略,你可以结合使用<subclass> 与<join>,如下所示:gQ3HTML5中文学习网 - HTML5先行者学习网

<class name="Payment" table="PAYMENT">  <id name="id" type="long" column="PAYMENT_ID">  <generator class="native"/>  </id>  <discriminator column="PAYMENT_TYPE" type="string"/>  <property name="amount" column="AMOUNT"/>  ...  <subclass name="CreditCardPayment" discriminator-value="CREDIT">  <join table="CREDIT_PAYMENT">  <property name="creditCardType" column="CCTYPE"/>  ...  </join>  </subclass>  <subclass name="CashPayment" discriminator-value="CASH">  <join table="CASH_PAYMENT">  ...  </join>  </subclass>  <subclass name="ChequePayment" discriminator-value="CHEQUE">  <join table="CHEQUE_PAYMENT" fetch="select">  ...  </join>  </subclass> </class> 

可选的声明fetch="select",是用来告诉Hibernate,在查询超类时, 不要使用外部连接(outer join)来抓取子类ChequePayment的数据。gQ3HTML5中文学习网 - HTML5先行者学习网

(责任编辑:)
推荐书籍
推荐资讯
关于HTML5先行者 - 联系我们 - 广告服务 - 友情链接 - 网站地图 - 版权声明 - 人才招聘 - 帮助