# Hibernate 4 中的实体继承模型

> 原文： [https://javabeginnerstutorial.com/hibernate/entity-inheritance-models-in-hibernate-4/](https://javabeginnerstutorial.com/hibernate/entity-inheritance-models-in-hibernate-4/)

上一次我们研究了将实体关系映射到数据库。 现在该关注主要的对象关系：继承。

如您所知，对象可以彼此继承，以将通用函数移到超类中，并且子代中只有不同部分。 使用 Hibernate 也可以实现相同的目的：您可以将通用函数分组到父类中，并且仅将差异添加到子类中，还可以将此关系映射到数据库。

## 这个示例

我将在书本中继续使用该示例-但这意味着该示例现在很难理解，但我尝试使其对您来说更舒适。

## 人，作者和出版者

首先，我考虑了书本继承法，但最后得出了一个简单的人继承模型，该模型既可以是作者又可以是出版者。 每个人都有一个名字（这是主要标识符）和一个电子邮件地址。

作者维护一份书面书籍清单以及其出版者的参考文献（每个作者只能有一个出版者）。 出版商具有税号和其作者列表。

## 单表继承

第一个继承模型是**单个表**。 它将每个子类（顾名思义）存储在单个数据库表中。 这意味着您不能在子类的必需列上应用数据库级别的约束，因为其他子类没有此字段，这将引发完整性违例异常。

要告诉实体结构使用单表继承，请在基本实体的定义上添加以下代码：

```java
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
```

为了区分存储在单个表中的实体类型，Hibernate（通常是 JPA）使用**区分符列**。 如果未提供区分符列的定义，则 Hibernate 将使用名为`DTYPE`的字符串列，其长度为 **31** 个字符。

鉴别符列的默认值是实体的名称，因此在此示例中有两个鉴别符：`author`和`Publisher`。

通过使用`@DiscriminatorColumn`和`@DiscriminatorValue`，您可以覆盖这些默认值以适合您的架构和要求。

## 连接继承

第二种类型是**连接**继承。 在这种情况下，子类以 *ID* 作为公共标识符存储在单独的数据库表中，在这里，Hibernate 可以将请求的子代与基类一起连接。

要创建联接继承，只需将以下内容添加到父类定义中：

```java
@Inheritance(strategy = InheritanceType.JOINED)
```

## 每个类的表继承

第三种类型是每个类模型的**表**，其中每个实例都有自己的表，表中包含所有信息。 这意味着很大的冗余，并且违反了数据库规范化规则，因为每个实例的父类的所有信息都存储在单个表中。

示例作者存储`name`，`emailAdress`和`PublisherId`，而发布者存储`name`，`emailAdress`和`taxId`。

并且没有为抽象类创建用于存储人员的表，因为 Hibernate 知道`AbstractPerson`*实体是*抽象*，因此它不需要任何表来存储信息。

每个类的表继承可以与超类的以下注解一起使用：

```java
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
```

## 使用哪一个？

这取决于您的应用。 但是，我从未见过任何应用在应用中使用按类分配表的策略，只有连接表或单个表。 有时大的继承树会导致由 Hibernate 创建的大联接查询，有时比单表解决方案要慢。

但是，有时更好的方法是跳过 Hibernate 并手动创建查询，以加快结果收集的速度，并避免 Hibernate 对数据结构及其如何收集信息的假设。

## 总结

继承策略对于通过维护的面向对象设计将实体建模到数据库是很好的。 但这会导致来自 Hibernate 的查询很大且很慢，但这并不意味着您应该避免使用它们。

在下一篇文章中，我将向您展示如何使用 HQL 和 JPQL 编写自己的 Hibernate 查询，因​​为`main`方法中的当前查询不是最好的。

#### 代码下载

您可以从 Github [此处](https://github.com/JBTAdmin/Hibernate)下载特定章节的代码。

