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

Eclipse 快速上手 Hibernate 系列四:繼承映射策略之「每類層次一表」完整實戰

     編輯:Java 相關知識

Hibernate 繼承映射三大策略概覽

面對對象模型的繼承體系,Hibernate 提供三種映射策略:

  1. Table per Class Hierarchy(每類層次一表):單表存儲整個繼承樹,靠判別列區分類型 —— 本文重點
  2. Table per Subclass(每子類一表):父類一表,每子類一表,主鍵關聯
  3. Table per Concrete Class(每具體類一表):每具體類獨立表,有限制(如無多態查詢)

策略一實現簡單、支持多態查詢、報表友好,但耦合度高、空間浪費、深層次結構列爆炸。適用於繼承層次淺、屬性差異小、頻繁多態查詢的場景。

項目結構與環境準備

  • Java Project: InheritanceMapping,獨立源/輸出目錄,用戶庫 hibernate
  • MySQL 數據庫 HibernateTest,GBK 編碼,JDBC URL 需雙重轉義 &characterEncoding=GBK
  • Ant build.xml 整合 XDoclet 生成 .hbm.xml 與 hibernate.cfg.xml,SchemaExport 自建表

領域模型代碼(XDoclet 註解驅動)

父類 Animal.java

package javamxj.inheritance.one;

/**
 * @hibernate.class table="Animal" discriminator-value="Animal"
 * @hibernate.discriminator column="ANIMAL_TYPE" type="string" length="10"
 */
public abstract class Animal {
    private Long id;
    private String name;

    /** @hibernate.id column="ID" generator-class="hilo" unsaved-value="null" */
    public Long getId() { return id; }
    public void setId(Long id) { this.id = id; }

    /** @hibernate.property length="24" */
    public String getName() { return name; }
    public void setName(String name) { this.name = name; }

    public abstract void makeSound();
}

關鍵點:@hibernate.discriminator 定義判別列 ANIMAL_TYPE,discriminator-value 指定當前類在該列的值。

子類 Cat.java

package javamxj.inheritance.one;

/** @hibernate.subclass discriminator-value="Cat" */
public class Cat extends Animal {
    private String furColor;

    public void makeSound() { System.out.println("喵喵"); }

    /** @hibernate.property length="24" */
    public String getFurColor() { return furColor; }
    public void setFurColor(String furColor) { this.furColor = furColor; }
}

子類 Dog.java

package javamxj.inheritance.one;

/** @hibernate.subclass discriminator-value="Dog" */
public class Dog extends Animal {
    private String category;

    public void makeSound() { System.out.println("汪汪"); }

    /** @hibernate.property length="24" */
    public String getCategory() { return category; }
    public void setCategory(String category) { this.category = category; }
}

子類僅需 @hibernate.subclass 指定判別值,無需重複定義 id/name 映射。

Ant 構建腳本 build.xml 核心片段




    
    
        
        
    


    
    

自動生成文件解析

Animal.hbm.xml



  
    
    
    
    
      
    
    
      
    
  

單表 Animal 包含所有屬性,ANIMAL_TYPE 值為 Animal/Cat/Dog,子類專有列對其他類型行為 NULL。

hibernate.cfg.xml



  
    net.sf.hibernate.dialect.MySQLDialect
    jdbc:mysql://localhost:3306/HibernateTest?useUnicode=true&characterEncoding=GBK
    
  

SchemaExport 生成 SQL


drop table if exists Animal;
create table Animal (
  ID bigint not null,
  ANIMAL_TYPE varchar(10) not null,
  name varchar(24),
  furColor varchar(24),
  category varchar(24),
  primary key (ID)
);
create table hibernate_unique_key (next_hi integer);
insert into hibernate_unique_key values (0);

測試驗證 Demo.java


public class Demo {
    public static void main(String[] args) {
        SessionFactory sf = new Configuration().configure().buildSessionFactory();
        // 保存
        Session s = sf.openSession(); Transaction tx = s.beginTransaction();
        Cat cat = new Cat(); cat.setName("小白"); cat.setFurColor("白色"); s.save(cat);
        Dog dog = new Dog(); dog.setName("小黑"); dog.setCategory("京巴狗"); s.save(dog);
        tx.commit(); s.close();
        // 多態查詢
        s = sf.openSession(); tx = s.beginTransaction();
        List animals = s.find("from " + Animal.class.getName());
        for (Animal a : animals) {
            System.out.println("動物 '" + a.getName() + "' 所在類: " + a.getClass().getName());
            System.out.print("發出叫聲: "); a.makeSound();
        }
        tx.commit(); s.close();
    }
}

輸出:

動物 '小白' 所在類: javamxj.inheritance.one.Cat
發出叫聲: 喵喵
動物 '小黑' 所在類: javamxj.inheritance.one.Dog
發出叫聲: 汪汪

數據表中 furColor 對 Dog 為 NULL,category 對 Cat 為 NULL,驗證單表共享結構。

優缺點總結與選型建議

優點缺點
實現最簡單,無 Join 查詢類層次耦合:任一類增欄位皆改動同一表
原生支持多態查詢/關聯空間浪費:深層次結構導致稀疏列爆炸
報表/全表掃描極快需判別列標識具體類型

適用:繼承深度 ≤ 3、子類屬性少、頻繁多態查詢。不適用:深層次結構、子類屬性多、存儲敏感場景 —— 改用 Table per Subclass(下篇講解)。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved