当前位置: 移动技术网 > IT编程>开发语言>Java > Java的Hibernate框架中的继承映射学习教程

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

2019年07月22日  | 移动技术网IT编程  | 我要评论
一、继承映射 继承是面向对象很重要的特性,它实现了代码的服用,在关系模型中同样也有继承关系,这种继承关系其实可以看做是一种枚举关系,一种类型中可以枚举出很多子类型,这些子

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

201678100006100.png (335×264)

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

201678100040571.png (669×83)

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

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类。

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

<?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.分析结果
生成的mysql数据库表中不仅会添加animal的基本属性,而且会添加pig和bird的属性,因为在映射文件中使用<subclass>写出了所添加的属性,另外还添加了相应的鉴别器属性,所以在数据库中会添加对应的鉴别列,生成的表结构如下图:

201678100102347.png (618×220)

二、数据操作

1.写入数据
在进行数据读取和写入操作时需要注意类中的操作使用了

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和hql

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

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

<?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方法能够加载获得相应的对象类。

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查询
hql支持多态查询,这主要由于查询出的是一个真正的对象,并不会返回一个代理,所以hql支持多态查询,另外在查询时需要注意查询语句中不要使用表名,而是要使用类名称,hibernate会根据类名称将其映射为对应的表名称,如下:

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); 
 } 
} 

查询结果:

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_ 
我是小猪猪! 
我不是小猪猪! 
我是小猪猪! 
我不是小猪猪! 

三、继承映射三种策略
1. 每个类分层结构一张表(table per class hierarchy)

假设我们有接口payment和它的几个实现类: creditcardpayment, cashpayment, 和chequepayment。则“每个类分层结构一张表”(table per class hierarchy)的映射代码如下所示:

<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)约束。

2. 每个子类一张表(table per subclass)

对于上例中的几个类而言,采用“每个子类一张表”的映射策略,代码如下所示:

<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> 

需要四张表。三个子类表通过主键关联到超类表(因而关系模型实际上是一对一关联)。

3. 每个子类一张表(table per subclass),使用辨别标志(discriminator)

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

<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的数据。

如您对本文有疑问或者有任何想说的,请 点击进行留言回复,万千网友为您解惑!

相关文章:

验证码:
移动技术网