我刚刚注意到Hibernate中的这个bevahior并且发现它有点令人惊讶(以一种受欢迎的方式)。我有一个名为SyncItem
的实体类型,它作为许多其他实体的超类。继承策略设置为InheritanceType.JOINED
,因此超类中的所有字段都有一个表,子类表只包含子类中添加的任何字段,以及返回超类表的引用。
例如,我的SyncItem
表格如下:
mysql> describe syncItems;
+------------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+------------+--------------+------+-----+---------+----------------+
| id | bigint(20) | NO | PRI | NULL | auto_increment |
| hidden | bit(1) | NO | | NULL | |
| title | varchar(255) | NO | | NULL | |
| createDate | datetime | NO | | NULL | |
| modifyDate | datetime | YES | | NULL | |
| deleteDate | datetime | YES | | NULL | |
+------------+--------------+------+-----+---------+----------------+
如果我有一个Property
子类,它可能会得到一个像:
mysql> describe properties;
+--------------+--------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+--------------+--------------+------+-----+---------+-------+
| syncId | bigint(20) | NO | PRI | NULL | |
| propertyCode | varchar(255) | YES | | NULL | |
+--------------+--------------+------+-----+---------+-------+
现在我有十几个不同的子类,让我感到惊讶的是我有一个类似的查询:
@NamedQuery(
name="SyncItem.findByTitle",
query="SELECT s FROM SyncItem s WHERE s.title = :title")
当我写这篇文章的时候,我希望因为我从SyncItem
中选择,我只会得到超类表中包含的信息(即我会得到一个SyncItem
实例,而不是一个Property
实例)。但是,当我运行它时,我发现查询实际上返回了正确的子类实例。这很好,因为它使许多事情更容易实现。
但是,我想知道,JPA / Hibernate如何管理这个子类?它无法知道给定的标题是否会映射到Property
而不是其他内容,而且据我所知,它没有从syncItems
到properties
的直接映射(相反,它必须从properties
映射回syncItems
)。在执行此查询时,它是否与每个子类表进行连接?如果是这样那么这不会使查询非常昂贵吗?
所以是的,只是想知道幕后发生了什么。
答案 0 :(得分:4)
是的,它为每个子表执行加入。它很昂贵,但您可以使用其他两种策略来映射继承。
Here你可以找到一个参考文献:
联合策略通常是继承模型中最慢的。 检索任何子类需要一个或多个数据库连接,以及 存储子类需要多个INSERT或UPDATE语句
3种可用策略中的每一种都有其自身的优点和缺点(如果您希望节省空间而不是时间,或两者之间的妥协)。选择还取决于您将更频繁地对这些表执行的操作类型。在我粘贴的参考文献中,你会发现每个参考文献都有一个相当简单的解释。
答案 1 :(得分:1)
我相信它会加入所有子类。它可能比没有连接更昂贵,但没有那么多,因为密钥被索引,只有一个表将包含所需的密钥。使用继承将不可避免地有一些开销。
您可以查看SQL日志输出以便自己查看。