首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Hibernate 繼承關係映射策略詳解:Table Per Class、Joined、Single Table 深度比較

     編輯:Java 相關知識

前言

Hibernate 提供三種繼承映射策略,各有優劣,選型直接影響資料庫結構、查詢效能與維護成本。本文以 TItem (父) → TBook / TDVD (子) 為例,詳細對比三種策略的映射配置、生成表結構、查詢 SQL 及適用場景。

一、領域模型

public class TItem implements Serializable {
    private int id;
    private String manufacture;
    private String name;
    // getter/setter
}
public class TBook extends TItem { private int pageCount; }
public class TDVD extends TItem { private String regionCode; }

二、策略一:Table Per Concrete Class (隱式多態 / 獨立表)

2.1 映射配置 (三個獨立 .hbm.xml)

<class name="TItem" table="ITEM">
    <id name="id"><generator class="native"/></id>
    <property name="name"/> <property name="manufacture"/>
</class>

<class name="TBook" table="BOOK">
    <id name="id"><generator class="native"/></id>
    <property name="name"/> <property name="manufacture"/> <property name="pageCount"/>
</class>

<class name="TDVD" table="DVD">
    <id name="id"><generator class="native"/></id>
    <property name="name"/> <property name="manufacture"/> <property name="regionCode"/>
</class>

2.2 特點

  • 每個具體類一張表,父類屬性在每張子表冗余
  • 主鍵獨立生成,跨表 ID 可能重複
  • 多態查詢 from TItem 需 UNION 多表,效能差
  • 修改父類屬性需同步修改所有子表映射,維護成本高
  • 適用:子類極少、極少多態查詢、歷史系統遷移

三、策略二:Joined Subclass (連接表 / 正規化)

3.1 映射配置 (單一 .hbm.xml)

<class name="TItem" table="ITEM" polymorphism="explicit">
    <id name="id"><generator class="native"/></id>
    <property name="name"/> <property name="manufacture"/>
    <joined-subclass name="TBook" table="TBOOK">
        <key column="id"/>
        <property name="pageCount"/>
    </joined-subclass>
    <joined-subclass name="TDVD" table="TDVD">
        <key column="id"/>
        <property name="regionCode"/>
    </joined-subclass>
</class>

3.2 生成表結構

表名欄位
ITEMid (PK), name, manufacture
TBOOKid (PK, FK→ITEM), pageCount
TDVDid (PK, FK→ITEM), regionCode

3.3 特點

  • 資料正規化,無冗余,修改父類屬性只改 ITEM 表
  • 共享主鍵 (Foreign Key Generator),ID 全局唯一
  • 多態查詢產生 LEFT OUTER JOIN,查詢較慢 (隨子類增加)
  • 插入需寫入多表,事務開銷稍大
  • 適用:子類較多、頻繁修改父類、需正規化設計、可接受 JOIN 開銷

四、策略三:Single Table with Discriminator (單表 / 判別欄位)

4.1 映射配置

<class name="TItem" table="ITEM" polymorphism="explicit">
    <id name="id"><generator class="native"/></id>
    <discriminator column="category" type="string"/>
    <property name="name"/> <property name="manufacture"/>
    <subclass name="TBook" discriminator-value="BOOK">
        <property name="pageCount"/>
    </subclass>
    <subclass name="TDVD" discriminator-value="DVD">
        <property name="regionCode"/>
    </subclass>
</class>

4.2 生成表結構

欄位說明
id (PK)主鍵
category判別欄位:'BOOK' 或 'DVD'
name, manufacture父類屬性
pageCountTBook 專屬,DVD 行為 NULL
regionCodeTDVD 專屬,BOOK 行為 NULL

4.3 特點

  • 單表無 JOIN,查詢/插入/更新最快
  • 子類專屬欄位設為 NOT NULL 受限 (需可空)
  • 子類過多導致稀疏表、欄位爆炸、違反正規化
  • 磁碟空間浪費 (大量 NULL)
  • 適用:子類少 (≤5)、屬性差異小、極高讀寫效能要求、簡單業務

五、三策略綜合比較表

維度Table Per ClassJoined SubclassSingle Table
表數量N (每具體類一張)N+1 (父表+各子表)1
資料冗余高 (父屬性重複)無 (正規化)無 (但大量 NULL)
主鍵策略獨立生成共享 (Foreign Key)單一生成
多態查詢 SQLUNION ALLLEFT OUTER JOIN單表掃描 + WHERE discriminator
查詢效能最差中等最佳
寫入效能單表多表事務單表最快
Schema 變更影響需改所有子表只改父表只改單表 (鎖表風險)
推薦場景極少多態、遷移專案標準企業應用、正規化優先高併發讀寫、子類少

六、註解式配置對應 (JPA / Hibernate Annotations)

// Joined
@Entity @Inheritance(strategy = InheritanceType.JOINED)
public class TItem { @Id @GeneratedValue Long id; ... }
@Entity public class TBook extends TItem { int pageCount; }

// Single Table
@Entity @Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name = "category")
public class TItem { ... }
@Entity @DiscriminatorValue("BOOK") public class TBook extends TItem { ... }

// Table Per Class
@Entity @Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public class TItem { ... }

七、總結建議

  1. 預設優先 Joined Subclass:平衡正規化、效能、維護性。
  2. 讀寫極高頻、子類穩定少見 → Single Table。
  3. 避免 Table Per Class,除非歷史包袱或極特殊需求。
  4. 實際專案中常混用:核心領域模型用 Joined,日誌/審計類用 Single Table。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved