Hibernate 中一对一、多对一和一对多的默认获取类型

Posted

技术标签:

【中文标题】Hibernate 中一对一、多对一和一对多的默认获取类型【英文标题】:Default fetch type for one-to-one, many-to-one and one-to-many in Hibernate 【发布时间】:2014-12-23 10:14:31 【问题描述】:

hibernate 映射中的默认获取类型是什么?

我在探索之后了解到的是:

对于一对一来说,它是渴望。 对于一对多,它是 惰性

但在 Eclipse 中测试后,它对所有人都渴望。

这取决于我使用的是 JPA 还是 Hibernate?

【问题讨论】:

如果您仍然参与 JPA 主题 - 我用新答案更新了您的问题,因为旧答案对于当前的 Hibernate 版本已经过时。 【参考方案1】:

这取决于您使用的是 JPA 还是 Hibernate。

来自JPA 2.0 spec,默认为:

OneToMany: LAZY
ManyToOne: EAGER
ManyToMany: LAZY
OneToOne: EAGER

在休眠状态下,一切都是懒惰的

更新:

最新版本的 Hibernate 与上述 JPA 默认值保持一致。

【讨论】:

“在休眠状态下,一切都是懒惰的”,显然它在最近的版本中发生了变化。请参阅Alexander Rühl's answer below。 Hibernate 是 JPA 实现之一,所以一旦你使用了 Hibernate,你就在使用 JPA :) 这是一个流行的查询。 @Ashish Agarwal您能否更新答案的最后一行。在 Hibernate 中,它现在并不懒惰。 更新了有关最新 Hibernate 行为的帖子。 有一个更新,声称 eager 是每个映射的默认获取类型,在当前 5.x 和新的 6.x Hibernate 文档中的第 11.3 章反驳了这一点,所以我撤消了编辑。此外,不建议使用自动渴望,因为这意味着在获取单个对象时可能会选择整个数据库。【参考方案2】:

我知道在提出问题时答案是正确的 - 但由于人们(就像我现在一样)仍然碰巧发现他们想知道为什么他们的 WildFly 10 表现不同,我想为当前 Hibernate 5.x 版本:

在Hibernate 5.2 User Guide 中,在11.2 章中有说明。应用获取策略

Hibernate 建议静态标记所有关联 懒惰并使用动态获取策略来获得渴望。这是 不幸的是,它与定义了这一点的 JPA 规范不一致 所有一对一和多对一的关联都应该被急切地获取 默认情况下。 Hibernate 作为一个 JPA 提供者,尊重这个默认值。

因此,Hibernate 的行为也类似于上述 JPA 的 Ashish Agarwal:

OneToMany: LAZY
ManyToOne: EAGER
ManyToMany: LAZY
OneToOne: EAGER

(见JPA 2.1 Spec)

【讨论】:

如果我们使用原生 hibernate 而不是 JPA impl,它的行为方式是否相同? @jMounir:嗯,我没有尝试过,但是由于 Hibernate 声明它的行为类似于 JPA 中定义的行为,我不明白为什么在单独使用 Hibernate 时会有所不同。在这两种情况下都可以覆盖默认策略。【参考方案3】:

为了回答您的问题,Hibernate 是 JPA 标准的一种实现。 Hibernate 有自己的操作怪癖,但根据 Hibernate docs

默认情况下,Hibernate 对集合使用惰性选择获取,对单值关联使用惰性代理获取。这些默认值适用于大多数应用程序中的大多数关联。

因此,无论您声明了何种类型的关系,Hibernate 将始终使用延迟获取策略加载任何对象。它将为一对一或多对一关系中的单个对象使用惰性代理(应该未初始化但不为空),以及一个空集合,当您尝试访问它时它将与值水合.

应该理解,Hibernate 只会在您尝试访问对象时尝试用值填充这些对象,除非您指定fetchType.EAGER

【讨论】:

【参考方案4】:

对于单值关联,即一对一和多对一:- 默认懒惰=代理 代理延迟加载:- 这意味着您的关联实体的代理对象已加载。这意味着只为关联实体的代理对象加载连接两个实体的 id。 例如:A 和 B 是具有多对一关联的两个实体。即:每个 B 可能有多个 A。A 的每个对象都将包含 B 的引用。 `

public class A
    int aid;
    //some other A parameters;
    B b;

public class B
    int bid;
     //some other B parameters;

`关系 A 将包含列(实体 A 的辅助、投标、...其他列)。 关系 B 将包含列(出价,...实体 B 的其他列) 代理意味着当获取 A 时,仅获取 B 的 id 并存储到 B 的仅包含 id 的代理对象中。 B 的代理对象是代理类的对象,它是 B 的子类,只有最少的字段。 由于 bid 已经是关系 A 的一部分,因此不必触发查询来从关系 B 中获取 bid。 实体 B 的其他属性只有在访问 bid 以外的字段时才会延迟加载。

对于集合,即多对多和一对多:- 默认懒惰=真 另请注意,获取策略(选择、加入等)可以覆盖惰性。 即:如果lazy='true' 和fetch='join',则获取A 也会获取B 或Bs(如果是集合)。仔细想想就知道原因了。 单值关联的默认获取是“加入”。 集合的默认提取是“选择”。 请验证最后两行。我已经从逻辑上推断出来了。

【讨论】:

以上是关于Hibernate 中一对一、多对一和一对多的默认获取类型的主要内容,如果未能解决你的问题,请参考以下文章

我们如何在 Keras 中定义一对一、一对多、多对一和多对多的 LSTM 神经网络? [复制]

hibernate中配置单向多对一关联,和双向一对多

如何在春季配置多对一和一对多关系? Hibernate会无限调用同一查询

Hibernate 多对一和一对多嵌套,会查出很多数据怎么办

hibernate入门三之关联映射(一对多和多对一)

Hibernate中一对多和多对一关系