Hibernate 的 Table Per Class(每个类一张表) 是继承映射策略之一,适用于面向对象的继承关系在关系型数据库中的实现。其核心思想是:为继承体系中的每一个具体子类单独创建一张数据库表,父类的属性会冗余存储在每个子类表中。以下是详细解析:
📌 一、核心机制
表结构设计
- 父类(抽象或非抽象)不生成对应的表,其属性会被复制到所有子类表中。
- 每个子类(包括具体子类和中间抽象类)对应一张独立的表,表中包含自身属性和继承的父类属性。
主键生成
所有子类表使用相同的主键列名和值,确保通过父类 ID 能跨表关联数据(需配合@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
注解)。查询逻辑
- 查询父类时,Hibernate 会执行
UNION ALL
合并所有子类表数据(性能较低); - 查询具体子类时,直接操作对应单表,效率较高 。
- 查询父类时,Hibernate 会执行
⚡ 二、使用示例
// 父类(不生成表)
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
@MappedSuperclass
public abstract class Animal {
@Id @GeneratedValue
private Long id;
private String name;
// getters/setters
}
// 子类1(生成独立表)
@Entity
@Table(name = "cat")
public class Cat extends Animal {
private int whiskerLength;
// getters/setters
}
// 子类2(生成独立表)
@Entity
@Table(name = "dog")
public class Dog extends Animal {
private String barkVolume;
// getters/setters
}
生成的表结构:
cat
表:含id
(主键)、name
(继承)、whisker_length
(自身)dog
表:含id
(主键)、name
(继承)、bark_volume
(自身)
⚖️ 三、优缺点对比
优点 | 缺点 |
---|---|
✅ 符合直观设计,子类数据独立存储 | ❌ 父类属性冗余存储,浪费空间 |
✅ 支持多态查询(需用 UNION ) |
❌ 父类查询性能差(全表扫描) |
✅ 子类表可单独优化索引/约束 | ❌ 无法通过外键约束保证数据一致性 |
🔍 四、适用场景
- 子类差异大:子类有大量独有属性,且父类属性较少(冗余成本低)。
- 高频查询子类:业务主要操作具体子类,避免父类查询的
UNION
开销 。 - 遗留数据库适配:需映射已存在的“每个类对应表”的数据库设计 。
💡 五、与其他策略对比
策略 | Table Per Class | Single Table | Joined Table |
---|---|---|---|
表数量 | 子类数量(父类无表) | 1(所有类共用) | 父类+子类各1表 |
查询性能 | 子类快,父类慢 | 最快(无连接) | 最慢(多表连接) |
数据冗余 | 父类属性冗余 | 所有字段可能冗余 | 无冗余 |
建议:优先测试
Joined Table
和Single Table
,仅在明确需要子表隔离时选择Table Per Class
。