拨开荷叶行,寻梦已然成。仙女莲花里,翩翩白鹭情。
IMG-LOGO
主页 文章列表 Hibernate @LazyCollection批注的用法

Hibernate @LazyCollection批注的用法

白鹭 - 2021-11-24 659 0 0

1.概述

从我们的应用程序管理SQL语句是我们需要照顾的最重要的事情之一,因为它对性能有巨大的影响。处理对象之间的关系时,有两种主要的设计模式可用于获取。第一个是懒惰的方法,而另一个是急切的方法。

在本文中,我们将对两者进行概述。另外,我们将在Hibernate中@LazyCollection

2.延迟获取

当我们想推迟数据初始化直到需要它时,我们使用延迟获取。让我们看一个例子,以更好地理解这个想法。

假设我们有一家在城市拥有多个分支机构的公司。每个分支机构都有自己的员工。从数据库的角度来看,这意味着我们与分支机构及其员工之间存在一对多的关系。

在惰性获取方法中,一旦获取分支对象,我们就不会获取员工。我们仅获取分支对象的数据,并且推迟加载僱员列表,直到调用getEmployees()方法为止。届时,将执行另一个数据库查询以获取员工。

这种方法的好处是我们减少了最初加载的数据量。原因是我们可能不需要分支机构的员工,并且加载它们没有意义,因为我们不打算立即使用它们。

3.预先获取

当数据需要立即加载时,我们会使用预先获取的方式。让我们以公司,分支机构和员工的相同示例来解释这个想法。一旦从数据库中加载了一些分支对象,我们将立即使用相同的数据库查询来加载其僱员列表。

使用紧急获取时的主要问题是,我们加载了可能不需要的大量数据。因此,只有在确定一旦加载对象便始终使用急切获取的数据时,才应使用它。

4. @LazyCollection批注

当我们需要照顾应用程序的性能时,可以使用@LazyCollection从Hibernate 3.0开始,默认情况下启用@LazyCollection @LazyCollection的主要思想是控制是否应该使用延迟获取方法还是预先获取的方法来获取数据。

使用@LazyCollection LazyCollectionOption设置提供了三个配置选项TRUEFALSEEXTRA 。让我们分别讨论它们。

4.1 使用LazyCollectionOption.TRUE

该选项为指定的字段启用了延迟获取方法,并且是从Hibernate版本3.0开始的默认选项。因此,我们不需要显式设置此选项。但是,为了更好地解释该想法,我们将以设置此选项为例。

在此示例中,我们有一个Branch实体,该实体由idnameEmployee实体@OneToMany关系组成。我们可以注意到,在此示例中@LazyCollection选项显式true

@Entity

 public class Branch {



 @Id

 private Long id;



 private String name;



 @OneToMany(mappedBy = "branch")

 @LazyCollection(LazyCollectionOption.TRUE)

 private List<Employee> employees;



 // getters and setters

 }

现在,让我们看一下Employee实体, idnameaddress以及Branch实体@ManyToOne关系组成:

@Entity

 public class Employee {



 @Id

 private Long id;



 private String name;



 private String address;



 @ManyToOne

 @JoinColumn(name = "BRANCH_ID")

 private Branch branch;



 // getters and setters

 }

在上面的示例中,当我们获得分支对象时,我们不会立即加载employee列表。相反,此操作将推迟到我们调用getEmployees()方法之前。

4.2 使用LazyCollectionOption.FALSE

当我们将此选项设置为FALSE ,我们启用了渴望的获取方法。在这种情况下,我们需要显式指定此选项,因为我们将覆盖Hibernate的默认值。让我们看另一个例子。

在这种情况下,我们具有Branch实体,该实体包含idname和与Employee实体@OneToMany请注意,我们将@LazyCollection的选项设置为FALSE

@Entity

 public class Branch {



 @Id

 private Long id;



 private String name;



 @OneToMany(mappedBy = "branch")

 @LazyCollection(LazyCollectionOption.FALSE)

 private List<Employee> employees;



 // getters and setters

 }

在上面的示例中,当我们获得分支对象时,我们会立即将僱员列表加载到分支中

4.3 使用LazyCollectionOption.EXTRA

有时,我们只关心集合的属性,而无需立即使用其中的对象。

例如,回到BranchEmployee的示例,我们可能只需要分支中的僱员数,而无需关心实际僱员的实体。在这种情况下,我们考虑使用EXTRA选项。让我们更新示例以处理这种情况。

与之前的情况类似, Branch实体与Employee实体idname@OneToMany但是,我们将@LazyCollection EXTRA

@Entity

 public class Branch {



 @Id

 private Long id;



 private String name;



 @OneToMany(mappedBy = "branch")

 @LazyCollection(LazyCollectionOption.EXTRA)

 @OrderColumn(name = "order_id")

 private List<Employee> employees;



 // getters and setters



 public Branch addEmployee(Employee employee) {

 employees.add(employee);

 employee.setBranch(this);

 return this;

 }

 }

我们注意到在这种情况下,我们使用了@OrderColumn原因是只有索引列表集合才考虑EXTRA这意味着如果我们不使用@OrderColumn,注释字段,则EXTRA选项将为我们提供与lazy相同的行为,并且在首次访问该集合时将对其进行提取。

另外,我们还定义了addEmployee()方法,因为我们需要让BranchEmployee从两侧同步。如果添加新Employee并为其设置分支机构,则还需要更新Branch

现在,当持久保留一个Branch实体时,我们需要将代码编写为:

entityManager.persist(

 new Branch().setId(1L).setName("Branch-1")



 .addEmployee(

 new Employee()

 .setId(1L)

 .setName("Employee-1")

 .setAddress("Employee-1 address"))



 .addEmployee(

 new Employee()

 .setId(2L)

 .setName("Employee-2")

 .setAddress("Employee-2 address"))



 .addEmployee(

 new Employee()

 .setId(3L)

 .setName("Employee-3")

 .setAddress("Employee-3 address"))

 );

如果我们看一下已执行的查询,我们会注意到Hibernate将首先为Branch-1 Branch然后它将插入Employee-1,Employee-2,然后是Employee-3。

我们可以看到这是自然的行为。 EXTRA选项的不良行为是在刷新了上述查询后,它将执行另外三个查询–我们添加的Employee

UPDATE EMPLOYEES

 SET

 order_id = 0

 WHERE

 id = 1



 UPDATE EMPLOYEES

 SET

 order_id = 1

 WHERE

 id = 2



 UPDATE EMPLOYEES

 SET

 order_id = 2

 WHERE

 id = 3

UPDATE语句以设置List条目索引。这是所谓的N +1查询问题的一个示例,这意味着我们执行N其他SQL语句来更新我们创建的相同数据。

从示例中我们注意到, EXTRA选项N +1查询问题。

另一方面,使用此选项的好处是当我们需要获取每个分支的僱员列表的大小时:

int employeesCount = branch.getEmployees().size();

当我们调用此语句时,它将仅执行以下SQL语句:

SELECT

 COUNT(ID)

 FROM

 EMPLOYEES

 WHERE

 BRANCH_ID = :ID

如我们所见,我们不需要将员工列表存储在内存中即可获取其大小。不过,我们建议避免使用EXTRA选项,因为它会执行其他查询。

在这里还值得注意的是N +1查询问题,因为它不仅限于JPA和Hibernate。

5.结论

在本文中,我们讨论了使用Hibernate从数据库中获取对象属性的不同方法。

首先,我们以一个示例讨论了延迟获取。然后,我们更新了示例以使用渴望获取并讨论了差异。

最后,我们展示了一种获取数据的额外方法,并说明了其优缺点。

标签:

0 评论

发表评论

您的电子邮件地址不会被公开。 必填的字段已做标记 *