什么是Hibernate中的延迟加载?

roc*_*ker 170 java orm hibernate lazy-loading

什么是Java中的延迟加载?我不明白这个过程.任何人都可以帮我理解延迟加载的过程吗?

Tho*_*zer 262

假设您有父母,并且该父母有一个孩子的集合.Hibernate现在可以"延迟加载"子进程,这意味着它在加载父进程时实际上并没有加载所有子进程.相反,它会在请求时加载它们.你可以明确地请求它,或者这更常见,当你试图访问一个孩子时,hibernate会自动加载它们.

延迟加载可以帮助显着提高性能,因为通常您不需要孩子,因此不会加载它们.

还要注意n + 1问题.当您访问集合时,Hibernate实际上不会加载所有子节点.相反,它将单独加载每个孩子.迭代集合时,会导致查询每个子集.为了避免这种情况,您可以通过调用parent.getChildren().size()来欺骗hibernate同时加载所有子节点.

  • 什么伎俩!! parent.getChildren()大小(); +1 (83认同)
  • 声明"当你访问集合......它将单独加载每个孩子"实际上是完全不准确的.它实际上恰恰相反.parent.getChildren()的任何解除引用都将导致Hibernate在一个db查询中加载集合中的所有子节点.除非你使用了非常特殊的"额外懒惰"延迟加载提示.或者,除非您将集合缓存在二级缓存中,并且相关的子级也不会缓存. (14认同)
  • 或者,应该使用Hibernate.initialize(parent.getChildren()) (5认同)

Bal*_*usC 72

"延迟加载"表示只有在您一次实际访问实体时才会加载实体.

模式是这样的:

public Entity getEntity() {
    if (entity == null) {
        entity = loadEntity();
    }
    return entity;
}
Run Code Online (Sandbox Code Playgroud)

这样可以节省预先加载/预填充大型数据集中所有实体的成本,而您实际上并不需要全部实体.

在Hibernate中,您可以配置为延迟加载子实体的集合.在实际的延迟加载随后的方法内部完成PersistentSet这Hibernate使用"下罩"指定实体的集合Set.

例如

public class Parent {
    private Set<Child> children;

    public Set<Child> getChildren() {
        return children;
    }
}
Run Code Online (Sandbox Code Playgroud)

.

public void doSomething() {
    Set<Child> children = parent.getChildren(); // Still contains nothing.

    // Whenever you call one of the following (indirectly), 
    // Hibernate will start to actually load and fill the set.
    children.size();
    children.iterator();
}
Run Code Online (Sandbox Code Playgroud)


Pas*_*ent 24

Martin Fowler 在企业应用程序架构模式中定义了Lazy Load模式:

一个对象,它不包含您需要的所有数据,但知道如何获取它.

因此,在加载给定对象时,我们的想法是不要急于加载您可能不会立即使用的相关对象来保存相关的性能成本.相反,只有在使用时才会加载相关对象.

这不是特定于数据访问和Hibernate的模式,但它在这些字段中特别有用,并且Hibernate支持一对多关联和一点关联(一对一和多对一)的延迟加载在一定条件下.在Hibernate 3.0参考文档的第19章中更详细地讨论了惰性交互.


小智 15

默认延迟加载是真的.延迟加载意味着当执行选择查询时它不会命中数据库.它将等待getter函数,即当我们需要时,它将从数据库中获取.例如:你是一个有很多玩具的孩子的父母.但是当前的问题是每当你打电话给他时(我们假设你有一个男孩),他也带着他所有的玩具来找你.现在这是一个问题,因为你不希望他一直带着他的玩具.因此,作为理性的父母,你要向前走,并将孩子的玩具定义为LAZY.现在每当你打电话给他时,他就会在没有玩具的情况下来找你.


Bha*_*hah 11

延迟提取决定在加载父对象时是否加载子对象.您需要这样设置父类的相应hibernate映射文件. Lazy = true(表示不加载子)默认情况下,子对象的延迟加载为true.

这样可以确保不加载子对象,除非通过getChild()在parent上调用方法在应用程序中显式调用它们.在这种情况下,hibernate会getChild()在父对象上执行动作时发出新的数据库调用来加载子对象.

但在某些情况下,您需要在加载父项时加载子对象.只需使lazy = false,hibernate将在从数据库加载父级时加载子级.

示例:如果您有一个TABLE?EMPLOYEE映射到Employee对象并包含一组Address对象.父类:Employee类,子类:地址类

public class Employee { 
private Set address = new HashSet(); // contains set of child Address objects 
public Set getAddress () { 
return address; 
} 
public void setAddresss(Set address) { 
this. address = address; 
} 
} 
Run Code Online (Sandbox Code Playgroud)

在Employee.hbm.xml文件中

<set name="address" inverse="true" cascade="delete" lazy="false"> 
<key column="a_id" /> 
<one-to-many class="beans Address"/> 
</set> 
Run Code Online (Sandbox Code Playgroud)

在上面的配置中.如果lazy="false": - 当您加载Employee对象时,也会加载时间子对象Address并将其设置为setAddresss()方法.如果你调用employee.getAdress()然后加载数据返回.没有新的数据库调用.

如果lazy="true": - 这是默认配置.如果你不提,那么hibernate认为lazy = true.当您加载Employee对象时,未加载时间子对象Adress.您需要额外调用数据库才能获取地址对象.如果您调用employee.getAdress()那时数据库查询将触发并返回结果.新鲜数据库调用.


小智 9

用外行的语言来说,就像你正在做蛋糕一样,你需要冰箱里的5-10种食材.您有两种选择,从冰箱中取出所有食材并将其放在厨房平台上,或在需要时带上您想要的食物.

类似地,在急切加载中,您获取有关bean及其相关类的所有信息(不是子项或is-a关系,但有关系,即蛋糕有面粉,有牛奶,有奶油等),并且在延迟加载的情况下,首先你只带来来自同一张桌子的标识符和价值(必要的成分,如果蛋糕,你需要先放在你的碗里).来自其他表的所有信息将在需要/使用时获取.


Ste*_*fen 8

懒惰加载?好吧,它只是意味着不会立即获取子记录,而是在您尝试访问它们时自动获取.


Vla*_*cea 7

延迟加载允许您推迟关联检索或更好地控制获取策略。

当您使用 EAGER 加载时,您定义了一个无法在查询时覆盖的全局获取计划,这意味着您仅限于在设计实体模型时做出的决定。该EAGER抓取是一个代码味道,因为抓取策略是查询时策略,它可能从一个业务用例的不同而异。

抓取策略是一个非常重要的方面,因为太多EAGER取会导致严重的性能相关的问题。