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

149

在Hibernate映射中,默认的获取类型是什么?

经过我的探索,我得到的信息如下:

  • 对于一对一关系,它是立即加载(eager)
  • 对于一对多关系,它是延迟加载(lazy)

但在Eclipse中测试后,所有都是立即加载。

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


1
如果您仍然参与JPA相关话题 - 我已经更新了您的问题,并提供了一个新答案,因为旧答案对于当前的Hibernate版本来说已经过时。 - Alexander Rühl
4个回答

285

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

根据JPA 2.0规范,默认值为:

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

而在Hibernate中,一切都是“懒”的

更新:

Hibernate的最新版本与上述JPA默认值相符。


18
在休眠模式下,一切都是懒加载的,显然在最近的版本中发生了改变。请参见下面亚历山大·鲁尔(Alexander Rühl)的答案 - Dinei
2
Hibernate是JPA的实现之一,因此一旦您使用Hibernate,就是在使用JPA :) - xenteros
这是一个常见的查询。@Ashish Agarwal,你能否更新你的答案的最后一行。在Hibernate中,现在并不是所有情况都是Lazy。 - Saurabh Tiwari
更新了关于最新Hibernate行为的帖子。 - M A
有一个更新,声称急切加载是每个映射的默认获取类型,但在当前的5.x和新的6.x Hibernate文档的第11.3章中都被驳斥了,因此我撤销了编辑。此外,不建议自动渴望,因为这意味着在获取单个对象时可能选择整个数据库。 - Alexander Rühl

61

我知道问题提出时回答是正确的 - 但由于人们(比如我现在)仍然在想为什么他们的 WildFly 10 表现不同,我想为当前的 Hibernate 5.x 版本提供更新:

Hibernate 5.2 用户指南 的第11.2章节中指出:

Hibernate 建议静态标记所有关联项为 lazy,并对渴望使用动态获取策略。不幸的是,这与 JPA 规范相悖,规定了默认情况下应急切地获取所有一对一和多对一的关联项。作为 JPA 提供程序,Hibernate 遵守该默认设置。

因此,Hibernate 的行为与上面 Ashish Agarwal 关于 JPA 的说法相似:

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

请参阅JPA 2.1规范


如果我们使用本地的Hibernate而不是JPA实现,它是否会以相同的方式运作呢? - jMounir
@jMounir:嗯,我没有尝试过那个,但既然Hibernate声明它的行为与JPA中定义的相同,我不认为在使用Hibernate本身时会有什么不同。在这两种情况下,都可以覆盖默认策略。 - Alexander Rühl

17
为了回答你的问题,Hibernate是JPA标准的一个实现。Hibernate有自己的操作特点,但根据 Hibernate文档 的描述:

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

因此,无论您声明了什么类型的关系,Hibernate始终将使用惰性获取策略来加载任何对象。它将在一对一或多对一关系中使用惰性代理(应该未初始化但不为null),并使用null集合,在您尝试访问它时填充它们的值。
需要了解的是,除非您指定fetchType.EAGER,否则Hibernate只会在您尝试访问对象时尝试填充这些对象的值。

2

对于单值关联,即一对一和多对一:
默认的Lazy=proxy
代理懒加载:这意味着一个与您关联实体的代理对象被加载。这意味着仅为关联实体的代理对象加载连接两个实体的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将包含列(aid,bid,...实体A的其他列)。
关系B将包含列(bid,...实体B的其他列)。
代理意味着当获取A时,仅获取B的ID并存储到B的代理对象中,该代理对象仅包含最少的字段。
B的代理对象是一个代理类的对象,该代理类是B的子类,只有最小的字段。
由于bid已经是关系A的一部分,因此不需要从关系B中发出查询以获取bid。
只有在访问除bid之外的字段时才惰性地加载实体B的其他属性。
对于集合,即多对多和一对多:
默认Lazy=true


请注意,提取策略(select,join等)可以覆盖lazy。
即:如果lazy='true'且fetch='join',则提取A也将提取B或Bs(在集合的情况下)。 如果您思考一下,就可以得到原因。
单值关联的默认提取为“join”。
集合的默认提取为“select”。请验证最后两行。我是这样推断的。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接