在 Hibernate 中什么是延迟加载?

Java 中的延迟加载是什么?我不明白这个过程。有人能帮助我理解延迟加载的过程吗?

285030 次浏览

假设您有一个父亲或母亲,而该父亲或母亲有一个子女集合。Hibernate 现在可以“延迟加载”子级,这意味着它在加载父级时实际上不会加载所有子级。相反,它会在被请求时加载它们。您可以显式地请求它,或者(这种情况更常见) ,当您尝试访问子级时,hibernate 将自动加载它们。

延迟加载可以显著提高性能,因为通常不需要子代,所以不会加载它们。

还要小心 n + 1-问题。在访问集合时,Hibernate 实际上不会加载所有子级。相反,它将单独加载每个子级。在迭代集合时,这将导致对每个子级进行查询。为了避免这种情况,您可以欺骗 hibernate 同时加载所有子节点,例如通过调用 Parent.getChildren ()。尺寸()。

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

延迟加载是一种设计模式 常用于计算机编程 以推迟对象的初始化 直到需要的时候。 它可以有助于提高工作效率 程序的操作,如果正确和 适当地使用

维基百科

来自 hibernate.org 的 懒惰装载链接

“延迟加载”意味着当 事实上第一时间访问实体时,实体将被加载为 只有

模式是这样的:

public Entity getEntity() {
if (entity == null) {
entity = loadEntity();
}
return entity;
}

这节省了预先加载/预先填充大型数据集中的实体的成本,而实际上您并不需要它们的 所有

在 Hibernate 中,可以配置为延迟加载子实体集合。然后,在 PersistentSet的方法中执行 真的延迟加载,Hibernate 使用“在兜帽下”将实体集合分配为 Set

例如。

public class Parent {
private Set<Child> children;


public Set<Child> getChildren() {
return children;
}
}

.

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();
}

Martin Fowler 在 企业应用体系结构模式中对 懒虫模式的定义如下:

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

因此,当加载一个给定的对象时,其思想是不要使用相关的对象 急性负荷,因为您可能不会立即使用它们来节省相关的性能成本。相反,只有在使用时才加载相关对象。

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

Hiberante 支持实体和集合的惰性初始模式特性。 Hibernate 引擎只加载那些我们正在查询的对象,而不加载其他实体或集合。

在默认情况下,加载初始化提及的唯一子元素是 lazy.true 的情况下,父元素加载不支持子元素

延迟设置决定是否在加载父对象时加载子对象。您需要设置父类的各个 hibernate 映射文件。Lazy = true (意思是不加载子对象)默认情况下,子对象的延迟加载为 true。这样可以确保子对象不会被加载,除非在应用程序中通过对 Parent 对象调用 getChild ()方法显式地调用它们。在这种情况下,当对 Parent 对象实际调用 getChild ()时,hibernate 会发出一个新的数据库调用来加载子对象。但是在某些情况下,在加载父对象时,确实需要加载子对象。只要设置惰性 = false,并且在从数据库加载父元素时,hibernate 将加载子元素。如果不经常需要,User 类的 Address 子类可以变得懒惰。但是当你处理在线书店的书时,你可能需要加载 Book 的 Author 对象。

延迟设置决定是否在加载父对象时加载子对象。您需要设置父类的各个 hibernate 映射文件。Lazy = true (意思是不加载子对象)默认情况下,子对象的延迟加载为 true。

默认情况下,延迟加载为 true。延迟加载意味着当执行选择查询时,它不会到达数据库。它将等待 getter 函数,即当我们需要时,它将从数据库中获取。 例如: 你是一个有很多玩具的孩子的父母。但目前的问题是,无论你什么时候给他打电话(我们假设你有一个男孩) ,他都会带着他所有的玩具来找你。这是个问题,因为你不想让他一直带着他的玩具。 因此,作为理性的家长,你可以直接把孩子的玩具定义为懒惰。现在不管你什么时候打电话给他,他都不带玩具来找你。

延迟获取决定是否在加载父对象时加载子对象。 您需要设置父类的各个 hibernate 映射文件。 Lazy = true(意思是不加载子节点) 默认情况下,子对象的延迟加载为 true。

这样可以确保子对象不会被加载,除非在应用程序中通过在 Parent 对象上调用 getChild()方法显式地调用它们。在这种情况下,hibernate 会发出一个新的数据库调用来在实际调用 Parent 对象时加载子对象。

但是在某些情况下,在加载父对象时,确实需要加载子对象。 只要设置惰性 = false,并且在从数据库加载父元素时,hibernate 将加载子元素。

例如: 如果您有一个映射到 EMPLOYEE 对象并包含一组 Address 对象的 TABLE? 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;
}
}

在 Employee.hbm.xml 文件中

<set name="address" inverse="true" cascade="delete" lazy="false">
<key column="a_id" />
<one-to-many class="beans Address"/>
</set>

在上述配置中。 如果 lazy="false":-当您加载 Employee 对象时,也会加载子对象 Address 并将其设置为 setAddress ()方法。 如果调用 Employee.getAddress () ,则加载数据返回。

如果 lazy="true":-这是默认的配置。如果你没有提到,那么休眠考虑惰性 = 真。 当加载 Employee 对象时,未加载子对象 Address。您需要额外调用数据库来获取地址对象。 如果调用 employee.getAdress(),那么该时间数据库查询将触发并返回结果。

在外行人的语言,这就像你正在做一个蛋糕,你将需要5-10个成分从冰箱。你有两个选择,从冰箱里拿出所有的食材放在厨房的平台上,或者在你需要的时候带上你想要的东西。

同样的,在快速加载中,你会获取 bean 及其相关类的所有信息(不是 child 或 is-a 关系,而是一个关系,比如蛋糕有面粉,有牛奶,有奶油等等) ,如果是延迟加载,首先你只带来来自同一张表的标识符和值(必要的配料,首先你需要在你的碗中的情况下蛋糕)。来自其他表的所有信息将在需要/使用时获取。

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

在使用 EAGER 加载时,您定义了一个不能在查询时覆盖的全局获取计划,这意味着您仅限于在设计实体模型时所做的决策。EAGER 抓取是一种代码味道,因为获取策略是一种查询时策略,并且在不同的业务用例中可能有所不同。

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

它仅仅意味着加载当前需要的数据,而不是一次加载一大堆现在不会使用的数据。从而使应用程序加载时间比通常更快。

令人惊讶的是,没有一个答案提到在 hibernate 中是如何实现的。

惰性加载 是一种设计模式,由于性能原因,它可以在休眠中有效地使用,这涉及到以下技术。


1. 字节码检测 :

使用休眠 钩子增强基类定义,以拦截对该实体对象的所有调用。

在编译时或运行[加载]时完成

1.1 编译时间

  • 编译后时间操作

  • 主要是由 maven/ant 插件

1.2 运行时间

2. 代理服务器

Hibernate 返回的实体对象是实际类型的代理。

参见: Javassist 主要的思想是什么以及在哪里实际使用?