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