# Hibernate 延迟加载教程

> 原文： [https://howtodoinjava.com/hibernate/lazy-loading-in-hibernate/](https://howtodoinjava.com/hibernate/lazy-loading-in-hibernate/)

在任何应用中，Hiberate 都以急切或延迟模式从数据库读取数据。 **Hiberate 延迟加载**是指按需延迟加载数据时的策略。

## 1\. Hiberate 延迟加载 - 我们为什么需要它？

考虑一种常见的互联网 Web 应用：在线商店。 商店维护产品目录。 在最原始的级别上，可以将其建模为管理一系列产品实体的目录实体。 在一家大型商店中，可能有成千上万种产品归为各种重叠类别。

当客户端访问商店时，必须从数据库中加载目录。 我们可能不希望实现将代表成千上万种产品的每个实体中的每一个加载到内存中。 对于足够大的零售商，鉴于机器上可用的物理内存量，这甚至可能是不可能的。

即使这是可能的，也可能会削弱网站的性能。 相反，我们只希望加载目录，可能还需要加载类别。 仅当用户向下钻取类别时，才应从数据库中加载该类别中的一部分产品。

为了解决此问题，Hibernate 提供了一种名为**延迟加载**的工具。 启用后，仅当直接请求实体的关联实体时，才会加载它们。

## 2\. 延迟加载如何解决上述问题

现在，当我们了解了问题之后，让我们了解延迟加载实际上如何在现实生活中提供帮助。 如果我们考虑解决上面讨论的问题，那么我们将以以下方式访问类别（或目录）：

```java
//Following code loads only a single category from the database:
Category category = (Category)session.get(Category.class,new Integer(42));

```

但是，如果访问了该类别的所有产品，并且执行了延迟加载，则会根据需要从数据库中拉出产品。 例如，在以下代码段中，将加载关联的产品对象，因为在第二行中已明确引用了该产品。

```java
//Following code loads only a single category from the database
Category category = (Category)session.get(Category.class,new Integer(42));

//This code will fetch all products for category 42 from database - "NOW"
Set<Product> products = category.getProducts();

```

这解决了我们仅在需要时才加载产品的问题。

## 3\. 如何在 Hiberate 下启用延迟加载

在进一步进行操作之前，重要的是要重述延迟加载的默认行为，以防使用 Hiberate 映射和注解。

默认行为是紧急加载“属性值”和延迟加载“集合”。 如果您以前使用过普通的 Hibernate 2（映射文件），则默认情况下会急切加载所有引用（包括集合），这与您可能会记得的相反。

另请注意，[`@OneToMany`](https://howtodoinjava.com/hibernate/hibernate-one-to-many-mapping-using-annotations/)和`@ManyToMany`关联默认为`LAZY`加载； [`@OneToOne`](https://howtodoinjava.com/hibernate/hibernate-one-to-one-mapping-using-annotations/)和`@ManyToOne`默认为 EAGER 加载。 记住这一点很重要，以避免将来出现任何陷阱。

要显式启用延迟加载，必须在使用 Hiberate 注解时要延迟加载的关联上使用“`fetch = FetchType.LAZY`”。

一个 **hibernare 延迟加载示例**如下所示：

```java
@OneToMany( mappedBy = "category", fetch = FetchType.LAZY )
private Set<ProductEntity> products; 

```

与`"FetchType.LAZY"`平行的另一个属性是`"FetchType.EAGER"`，它与`LAZY`正好相反，即，当首次获取所有者实体时，它也会加载关联实体。

## 4\. 延迟加载在 Hiberate 下如何工作

Hibernate 可以在实体和关联上应用延迟加载行为的最简单方法是提供它们的代理实现。 Hibernate 通过替换从实体类派生的代理来拦截对实体的调用。 如果缺少所需信息，将从控制权移交给上级实体的实现之前将其从数据库中加载。

请注意，当关联表示为集合类时，将创建包装器（本质上是集合的代理，而不是集合所包含的实体），并替换为原始集合。 当您访问该集合代理时，您在返回的代理集合中得到的不是代理实体；它是代理实体。 而是它们是实际的实体。 您无需在理解此概念上施加太大压力，因为在运行时几乎没有关系。

## 5\. 延迟加载对分离实体的影响

如我们所知，Hiberate 只能通过会话访问数据库，因此，如果实体与会话分离，并且当我们尝试访问尚未加载的关联（通过代理或集合包装器）时，**Hibernate 抛出`LazyInitializationException`**。

解决方法是确保通过将实体附加到会话来使该实体再次成为持久化，或者确保在将实体从会话中分离之前，将访问所有需要的字段（将它们加载到实体中）。

这就是这个简单但非常重要的概念，即**如何在 Hiberate** 中加载延迟对象。 对于 **Hiberate 获取策略**[面试问题](https://howtodoinjava.com/java-interview-questions/)的初学者来说，这可能是一个问题。

如果不清楚或您想讨论任何事情，请发表评论。

学习愉快！