面對對象模型的繼承體系,Hibernate 提供三種映射策略:
策略一實現簡單、支持多態查詢、報表友好,但耦合度高、空間浪費、深層次結構列爆炸。適用於繼承層次淺、屬性差異小、頻繁多態查詢的場景。
InheritanceMapping,獨立源/輸出目錄,用戶庫 hibernateHibernateTest,GBK 編碼,JDBC URL 需雙重轉義 &characterEncoding=GBKbuild.xml 整合 XDoclet 生成 .hbm.xml 與 hibernate.cfg.xml,SchemaExport 自建表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 指定當前類在該列的值。
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; }
}
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 映射。
單表 Animal 包含所有屬性,ANIMAL_TYPE 值為 Animal/Cat/Dog,子類專有列對其他類型行為 NULL。
net.sf.hibernate.dialect.MySQLDialect
jdbc:mysql://localhost:3306/HibernateTest?useUnicode=true&characterEncoding=GBK
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);
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(下篇講解)。