Java的Hibernate框架中的繼承映射學(xué)習(xí)教程
一、繼承映射
繼承是面向?qū)ο蠛苤匾奶匦?,它?shí)現(xiàn)了代碼的服用,在關(guān)系模型中同樣也有繼承關(guān)系,這種繼承關(guān)系其實(shí)可以看做是一種枚舉關(guān)系,一種類(lèi)型中可以枚舉出很多子類(lèi)型,這些子類(lèi)型和父對(duì)象形成了繼承關(guān)系,能夠?qū)ζ溥M(jìn)行枚舉的大部分都可以看做是一種繼承映射,所以這種枚舉關(guān)系可以看做是繼承映射,例如動(dòng)物就是一種抽象類(lèi),它是其它動(dòng)物豬、貓等的父類(lèi),它們之間就是一種繼承關(guān)系,如下圖:

這種繼承映射在轉(zhuǎn)化為關(guān)系模型后會(huì)生成一張表,那么這張表是如何區(qū)分這兩種類(lèi)型的呢?用的是關(guān)系字段,需要在表中添加類(lèi)型字段,使用關(guān)鍵字來(lái)標(biāo)明對(duì)象的類(lèi)型。所以上圖中的對(duì)象模型對(duì)應(yīng)的表結(jié)構(gòu)如下:

在生成表結(jié)構(gòu)時(shí),需要添加對(duì)應(yīng)的字段類(lèi)型,所以需要在映射文件中添加對(duì)應(yīng)的映射鑒別器,這里就需要使用discriminator-value屬性。
1.類(lèi)文件
類(lèi)文件中沒(méi)有需要注意的地方,在編寫(xiě)時(shí)注意之間的繼承關(guān)系即可。
清單一:Animal類(lèi)代碼,只需要添加基本的屬性。
package com.src.hibernate;
public class Animal {
//id號(hào)
private int id;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
//名稱(chēng)
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類(lèi),添加基本的屬性,并繼承Animal類(lèi)。
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.映射文件
映射文件中需要添加對(duì)應(yīng)的映射,該模型中只需要添加一個(gè)映射文件,因?yàn)橹簧梢粡埍?,在映射文件中添加?duì)應(yīng)的子類(lèi)映射,使用<subclass>標(biāo)簽,標(biāo)簽中添加鑒別器discriminator-value,該鑒別器屬性指明了在數(shù)據(jù)庫(kù)中寫(xiě)入數(shù)據(jù)時(shí)指示寫(xiě)入的是何種類(lèi)型,如下:
<?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> <!-- 加入鑒別標(biāo)簽,且必須放在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.分析結(jié)果
生成的MySQL數(shù)據(jù)庫(kù)表中不僅會(huì)添加Animal的基本屬性,而且會(huì)添加Pig和Bird的屬性,因?yàn)樵谟成湮募惺褂?lt;subclass>寫(xiě)出了所添加的屬性,另外還添加了相應(yīng)的鑒別器屬性,所以在數(shù)據(jù)庫(kù)中會(huì)添加對(duì)應(yīng)的鑒別列,生成的表結(jié)構(gòu)如下圖:

二、數(shù)據(jù)操作
1.寫(xiě)入數(shù)據(jù)
在進(jìn)行數(shù)據(jù)讀取和寫(xiě)入操作時(shí)需要注意類(lèi)中的操作使用了
public void testSave(){
Session session=null;
try{
//創(chuàng)建session對(duì)象
session=HibernateUtils.getSession();
//開(kāi)啟事務(wù)
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.多態(tài)查詢(xún)--get和hql
基本的查詢(xún)方法,只需要使用load和get方法即可,這里重點(diǎn)討論多態(tài)查詢(xún)。多態(tài)查詢(xún)是指Hibernate在加載對(duì)象時(shí)能夠采用instanceof鑒別出其真正的類(lèi)型的對(duì)象即可為多態(tài)查詢(xún)。
Note:多態(tài)查詢(xún)不支持延遲加載,也就是說(shuō)如果使用load方法,需要在映射文件中將延遲加載設(shè)置為false。
3.load延遲加載
load支持延遲加載,在加載對(duì)象時(shí)其實(shí)生成的是對(duì)象的代理,所以在使用多態(tài)查詢(xún)時(shí)需要在映射文件中將延遲加載設(shè)置為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> <!-- 加入鑒別標(biāo)簽,且必須放在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加載該示例中支持多態(tài)查詢(xún),在配置文件中將延遲加載設(shè)置為false,所以這里使用load方法能夠加載獲得相應(yīng)的對(duì)象類(lèi)。
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());
//因?yàn)閘oad默認(rèn)支持lazy,所以我們看到的是Animal的代理
//所以采用了instanceof無(wú)法鑒別出真正的類(lèi)型Pig
//所以load在此情況下是不支持多態(tài)查詢(xún)的
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查詢(xún)
hql支持多態(tài)查詢(xún),這主要由于查詢(xún)出的是一個(gè)真正的對(duì)象,并不會(huì)返回一個(gè)代理,所以hql支持多態(tài)查詢(xún),另外在查詢(xún)時(shí)需要注意查詢(xún)語(yǔ)句中不要使用表名,而是要使用類(lèi)名稱(chēng),Hibernate會(huì)根據(jù)類(lèi)名稱(chēng)將其映射為對(duì)應(yīng)的表名稱(chēng),如下:
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);
}
}
查詢(xún)結(jié)果:
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. 每個(gè)類(lèi)分層結(jié)構(gòu)一張表(Table per class hierarchy)
假設(shè)我們有接口Payment和它的幾個(gè)實(shí)現(xiàn)類(lèi): CreditCardPayment, CashPayment, 和ChequePayment。則“每個(gè)類(lèi)分層結(jié)構(gòu)一張表”(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>
采用這種策略只需要一張表即可。它有一個(gè)很大的限制:要求那些由子類(lèi)定義的字段, 如CCTYPE,不能有非空(NOT NULL)約束。
2. 每個(gè)子類(lèi)一張表(Table per subclass)
對(duì)于上例中的幾個(gè)類(lèi)而言,采用“每個(gè)子類(lèi)一張表”的映射策略,代碼如下所示:
<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>
需要四張表。三個(gè)子類(lèi)表通過(guò)主鍵關(guān)聯(lián)到超類(lèi)表(因而關(guān)系模型實(shí)際上是一對(duì)一關(guān)聯(lián))。
3. 每個(gè)子類(lèi)一張表(Table per subclass),使用辨別標(biāo)志(Discriminator)
注意,對(duì)“每個(gè)子類(lèi)一張表”的映射策略,Hibernate的實(shí)現(xiàn)不需要辨別字段,而其他 的對(duì)象/關(guān)系映射工具使用了一種不同于Hibernate的實(shí)現(xiàn)方法,該方法要求在超類(lèi) 表中有一個(gè)類(lèi)型辨別字段(type discriminator column)。Hibernate采用的方法更 難實(shí)現(xiàn),但從關(guān)系(數(shù)據(jù)庫(kù))這點(diǎn)上來(lái)看,按理說(shuō)它更正確。若你愿意使用帶有辨別字 段的“每個(gè)子類(lèi)一張表”的策略,你可以結(jié)合使用<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",是用來(lái)告訴Hibernate,在查詢(xún)超類(lèi)時(shí), 不要使用外部連接(outer join)來(lái)抓取子類(lèi)ChequePayment的數(shù)據(jù)。
- 舉例講解Java的Hibernate框架中的多對(duì)一和一對(duì)多映射
- Java的Hibernate框架中一對(duì)多的單向和雙向關(guān)聯(lián)映射
- Java的Hibernate框架中復(fù)合主鍵映射的創(chuàng)建和使用教程
- Java的Hibernate框架中的組合映射學(xué)習(xí)教程
- Java的Hibernate框架中集合類(lèi)數(shù)據(jù)結(jié)構(gòu)的映射編寫(xiě)教程
- Hibernate映射解析之關(guān)聯(lián)映射詳解
- java Hibernate多對(duì)多映射詳解及實(shí)例代碼
- Hibernate映射之基本類(lèi)映射和對(duì)象關(guān)系映射詳解
- 詳解hibernate雙向多對(duì)多關(guān)聯(lián)映射XML與注解版
相關(guān)文章
idea2023遠(yuǎn)程調(diào)試springboot的過(guò)程詳解
這篇文章主要介紹了idea2023遠(yuǎn)程調(diào)試,本文通過(guò)圖文并茂的形式給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-08-08
使用Spirng Boot Admin監(jiān)控Spring Cloud應(yīng)用項(xiàng)目
這篇文章主要介紹了使用Spirng Boot Admin監(jiān)控Spring Cloud應(yīng)用項(xiàng)目,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-05-05
Invalid?bound?statement?(not?found)出現(xiàn)原因以及解決辦法
這篇文章主要給大家介紹了關(guān)于Invalid?bound?statement?(not?found)出現(xiàn)原因以及解決辦法的相關(guān)資料,文中給出了詳細(xì)的解決方法,需要的朋友可以參考下2023-07-07
Spring boot actuator端點(diǎn)啟用和暴露操作
這篇文章主要介紹了Spring boot actuator端點(diǎn)啟用和暴露操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-07-07
Spring中DAO被循環(huán)調(diào)用的時(shí)候數(shù)據(jù)不實(shí)時(shí)更新的解決方法
這篇文章主要介紹了Spring中DAO被循環(huán)調(diào)用的時(shí)候數(shù)據(jù)不實(shí)時(shí)更新的解決方法,需要的朋友可以參考下2014-08-08
情人節(jié)寫(xiě)給女朋友Java Swing代碼程序
這篇文章主要為大家分享了情人節(jié)寫(xiě)給女朋友的java小程序,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,祝大家每天都是情人節(jié)2018-02-02
Java 使用 HttpClient 發(fā)送 GET請(qǐng)求和 POST請(qǐng)求
本文主要介紹了Java 使用 HttpClient 發(fā)送 GET請(qǐng)求和 POST請(qǐng)求,文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-08-08

