JPA/Hibernate 支援三種繼承映射策略,對應資料庫不同的表結構設計。透過 @Inheritance 註解在父類別指定策略,搭配 @DiscriminatorColumn、@DiscriminatorValue、@PrimaryKeyJoinColumn 等註解微調細節。
@Entity
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public class A { @Id @GeneratedValue private int id; private String aname; }
@Entity
public class B extends A { private String bname; }
@Entity
public class C extends A { private String cname; }
生成 DDL:
create table A (id integer not null auto_increment, aname varchar(255), primary key (id))
create table B (id integer not null, aname varchar(255), bname varchar(255), primary key (id))
create table C (id integer not null, aname varchar(255), cname varchar(255), primary key (id))
特點:各子表獨立包含父屬性欄位,無關聯;查詢父類需 UNION 所有子表,效能較差;不支援 IDENTITY 自增策略 (需用 TABLE 或 SEQUENCE)。
@Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name = "mytype", discriminatorType = DiscriminatorType.STRING)
public class A { ... }
@Entity
@DiscriminatorValue("btype")
public class B extends A { ... }
@Entity
@DiscriminatorValue("ctype")
public class C extends A { ... }
生成 DDL:
create table A (id integer not null auto_increment, aname varchar(255), mytype varchar(31), bname varchar(255), cname varchar(255), primary key (id))
特點:所有類別共用一表,新增判別欄位 (DTYPE 或自訂 mytype);查詢效能最好,但子類特有欄位必須允許 NULL;大量子類導致表欄位膨脹。
@Entity
@Inheritance(strategy = InheritanceType.JOINED)
public class A { @Id @GeneratedValue private int id; private String aname; }
@Entity
@PrimaryKeyJoinColumn(name = "bid") // 可自訂子表 PK/FK 欄位名
public class B extends A { private String bname; }
@Entity
public class C extends A { private String cname; }
生成 DDL:
create table A (id integer not null auto_increment, aname varchar(255), primary key (id))
create table B (bname varchar(255), bid integer not null, primary key (bid))
create table C (cname varchar(255), id integer not null, primary key (id))
alter table B add constraint FK_B_A foreign key (bid) references A (id)
alter table C add constraint FK_C_A foreign key (id) references A (id)
特點:父表存共同屬性,子表存特有屬性 + PK/FK;符合正規化,查詢需 JOIN;支援 @PrimaryKeyJoinColumn 自訂 FK 欄位名,但不能關聯父表非主鍵欄位 (會報錯 SecondaryTable JoinColumn cannot reference a non primary key)。
使用 @MappedSuperclass,父類別不對應資料表,僅提供共同屬性給子類繼承:
@MappedSuperclass
public class BaseEntity { @Id @GeneratedValue private Long id; private String createdBy; }
@Entity
public class User extends BaseEntity { private String username; }
生成 DDL:User 表直接包含 id、createdBy、username,無 BaseEntity 表。
子類別可用 @AttributeOverride、@AssociationOverride 覆寫父類欄位定義 (如欄位名、長度等)。
| 策略 | 表數量 | 查詢效能 | 正規化 | 適用場景 |
|---|---|---|---|---|
| TABLE_PER_CLASS | 每類一表 | 差 (UNION) | 低 | 子類差異大、很少多型查詢父類 |
| SINGLE_TABLE | 單表 | 最好 | 低 | 繼承層次淺、欄位少、高頻多型查詢 |
| JOINED | 父表+各子表 | 中 (JOIN) | 高 | 需正規化、子類擴充性強 |