【Hibernate框架】三種繼承映射


一、綜述

       大家都知道,hibernate作為ORM框架的一個具體實現,最大的一個優點就是是我們的開發更加的能體現出“面向對象”的思想。在面向對象開發中,類與類之間是可以相互繼承的(單向繼承),而Hibernate中也對這種繼承關系提供了自己風格的封裝,這就是我們接下來要介紹的Hibernate繼承映射的三種策略:

以下UML圖類為例:

1、每棵類繼承樹一張表(可以理解為整棵樹一張表,表內有所有字段)

2、每個類一張表(父類、子類、子類各一張表,父表中有公共字段,子表中有個性字段+外鍵約束)

3、每個具體類一張表(每個子類一張表,每張表都有自己所有的屬性字段)

 

二、簡介三種繼承映射方式的實現:

實體類也就是我們的PO對象肯定是少不了的,這也是三種方式都必須要有的公共部分了算是:

 

Animal.Java:

[java]  view plain copy
 print?在CODE上查看代碼片派生到我的代碼片
  1. public class Animal {  
  2.     private int id;  
  3.     private String name;  
  4.     private String sex;  
  5.       
  6.     public int getId(){  
  7.           return id;  
  8.     }  
  9.     public void setId(int id){  
  10.           this.id=id;  
  11.     }  
  12.     public String getName(){  
  13.           return name;  
  14.     }  
  15.     public void setSex(String name){  
  16.           this.name=name;  
  17.     }  
  18.     public String getSex(){  
  19.           return sex;  
  20.     }  
  21.     public void setSex(String sex){  
  22.           this.sex=sex;  
  23.     }  
  24. }  

 

 

Pig.java:

 

[java]  view plain copy
 print?在CODE上查看代碼片派生到我的代碼片
  1. public class Pig extends Animal{  
  2.     private int weight;  
  3.     public int getWeight(){  
  4.           return weight;  
  5.     }  
  6.     public void setWeight(){  
  7.           this.weight=weight;  
  8.     }  
  9. }  

 

 

Bird.java:

[java]  view plain copy
 print?在CODE上查看代碼片派生到我的代碼片
  1. public class Bird extends Animal{  
  2.     private int height;  
  3.     public int getHeight(){  
  4.           return height;  
  5.     }  
  6.     public void setHeight(){  
  7.           this.height=height;  
  8.     }  
  9. }  

 

 

三、配置文件分析:

1、每棵類繼承樹一張表(可以理解為整棵樹一張表,表內有所有字段)

Extends.hbm.xml

[html]  view plain copy
 print?在CODE上查看代碼片派生到我的代碼片
  1. <hibernate-mapping package="com.ssh.hibernate">  
  2.     <class name="Animal">  
  3.         <id name="id">  
  4.             <generator class="native"/>  
  5.         </id>  
  6.         <discriminator column="type" type="string"></discriminator>  
  7.         <property name="name"/>  
  8.         <property name="sex"/>          
  9.         <subclass name="Pig" discriminator-value="Pig">  
  10.             <property name="weight"></property>               
  11.         </subclass>  
  12.         <subclass name="Bird" discriminator-value="Bird">  
  13.             <property name="height"></property>               
  14.         </subclass>          
  15.     </class>  
  16. </hibernate-mapping>  

 

 

配置映射文件時,父類還用<class>標簽來定義;添加的區分字段(比如上面表1中的Type字段)需要用<discriminator>標簽來定義;用<subclass>標簽定義兩個子類,與父類“合並”在同一張表里,子類的特有屬性用<property>屬性定義即可。

 

映射文件中的子類<subclass>標簽還可以與標簽同級,但是要加上屬性extends,屬性值為父類全路徑名稱。

 

[html]  view plain copy
 print?在CODE上查看代碼片派生到我的代碼片
  1. <hibernate-mapping package="com.ssh.hibernate">  
  2.     <class name="Animal">  
  3.         <id name="id">  
  4.             <generator class="native"/>  
  5.         </id>  
  6.         <discriminator column="type" type="string"></discriminator>  
  7.         <property name="name"/>  
  8.         <property name="sex"/>         
  9.     </class>  
  10.     <class name="Pig" discriminator-value="Pig" extends="com.ssh.vo.Animal">  
  11.         <property name="weight"></property>               
  12.     </class>  
  13.     <class name="Bird" discriminator-value="Bird" extends="com.ssh.vo.Animal">  
  14.         <property name="height"></property>               
  15.     </class>          
  16.       
  17. </hibernate-mapping>  

 

 

 

這種映射方式可以把多個類放在一張表中,但是粒度比較粗,有冗余字段;但又是因為多個類的相關記錄都存放在一張表中,查詢時不用關聯,因此效率較高。

 

 

2、每個類一張表(父類、子類、子類各一張表,父表中有公共字段,子表中有個性字段+外鍵約束)

Extends.hbm.xml

 

[html]  view plain copy
 print?在CODE上查看代碼片派生到我的代碼片
  1. <hibernate-mapping package="com.ssh.hibernate">  
  2.     <class name="Animal">  
  3.         <id name="id">  
  4.             <generator class="native"/>  
  5.         </id>  
  6.         <property name="name"/>  
  7.         <property name="sex"/>  
  8.         <joined-subclass name="Pig" table="t_pig">  
  9.             <key column="pid" />  
  10.             <property name="weight"/>  
  11.         </joined-subclass>  
  12.         <joined-subclass name="Bird" table="t_bird">  
  13.             <key column="bid"/>  
  14.             <property name="height"/>  
  15.         </joined-subclass>  
  16.     </class>  
  17. </hibernate-mapping>  

 

       這種方案相對於上層實現(增刪改查等操作)不變,因為對象模型並沒有改變,只是關系模型改了,只需要修改映射文件即可。缺點:查詢時需要關聯表,效率差;插入時也要執行多個insert語句,適合繼承程度不深的情況。優點:粒度較細,調理清楚,沒有冗余

3、每個具體類一張表(每個子類一張表,每張表都有自己所有的屬性字段)

Extends.hbm.xml

[html]  view plain copy
 print?在CODE上查看代碼片派生到我的代碼片
  1. <hibernate-mapping package="com.ssh.hibernate">  
  2.     <class name="Animal" abstract="true">  
  3.         <id name="id">  
  4.             <generator class="uuid"/>  
  5.         </id>  
  6.         <property name="name"/>  
  7.         <property name="sex"/>  
  8.         <union-subclass name="Pig" table="t_pig">  
  9.             <property name="weight"/>  
  10.         </union-subclass>  
  11.         <union-subclass name="Bird" table="t_bird">  
  12.             <property name="height"/>  
  13.         </union-subclass>  
  14.     </class>  
  15. </hibernate-mapping>  

 

 

上面的表有個特點就是,t_pig和t_bird的主鍵永遠都不會相同。因為表面上看起來這是兩張表,但實際上存儲的都是動物(同一類型),所以還可以看做是一張表。在配置文件中 <union-subclass>標簽中不需要key值了,注意Animal的主鍵生成策略不能是自增(native)了,如果自增的話,pig表中第一條記錄id為1,bird表中第一條記錄也為1,而它們在實際意義上屬於同一類型(可以看做在一張表中),否則可能造成不同子類對應表中的主鍵相同,所以主鍵不可一致。配置映射文件時,父類還用<class>標簽來定義;用<union-subclass>標簽定義兩個子類,且每個類對應的表的信息是完全的,包含了所有從父類繼承下來的屬性。子類的特有屬性同樣用<property>定義即可。用abstract屬性表示父類Animal為抽象類,這樣Animal就不會映射成表了。

 

四、總結:

       如果系統需要經常進行查操作且子類數量較多,則建議用第一種方案,即每棵生成樹映射一張表,這也是最常用的方法,效率較高。如果追求細粒度的設計且子類數量不多,則可以用后兩種方案:每個類映射一張表或每個具體類映射一張表。

        假如說我們就是有三張表,分別是T_Animal、T_Pig、T_Bird就是要求我們用sql語句來完成這些級聯,大家想過sql語句與hbm.xml配置文件的映射關系嗎?其實他就是幫我們做的表union和表join整合思想,大家可以思考一下這個問題。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM