延迟加载模式如何帮助提高性能?

时间:2019-01-08 03:02:46

标签: hibernate lazy-loading

假设我设置了lazy =“ true”,并且我正在尝试检索Employee的子记录(Employee是父项,而FamilyMember是其子项)

我的代码继续构建所有子记录的集合:

List<FamilyMember> familyMembers = new ArrayList<FamilyMember>();
Query query = session.createQuery("From FamilyMembers ...");
Iterator<FamilyMember> it = query.iterate();
while (it.hasNext()) {
    familyMembers.add(it.next());
}

据我所知,上述迭代只是构建了一个“代理”对象的集合(例如-5个FamilyMember对象的列表)。我的问题是-即使要构建集合,它也需要知道结果的大小(它还会获得子记录的关键字段值,以便在实际从代理中获取子记录时进一步使用),这将由某些查询返回(它会得到该结果)通过明显地击中数据库),休眠如何帮助节省性能开销?

进一步,假设一些代码可以获取物理记录:

FamilyMember member = familyMembers.get(2);

上一行应该获得哪个FamilyMember对象?这是否意味着在后台进行了一些与FamilyMember的关键字段的隐式映射?如果是,那么当我们实际上要获得相关密钥时,这会如何提高性能?请澄清。

2 个答案:

答案 0 :(得分:0)

延迟加载适用于通常通过联接注释应用延迟加载的实体中存在的集合/对象。

例如,如果您的Employee类如下:

class Employee{
.......
@OneToMany(fetch=FetchType.LAZY)
private List<FamilyMember> familyList;
.......
}

如果您通过休眠方式获取Employee实体,则familyList仅在您尝试访问其数据或显式调用hibernate.initialize时才填充数据。这将使查询更快地获取多个雇员,因为它不会加载与每个雇员相关联的所有FamilyMember列表。

您可以在以下位置了解更多信息: Hibernate lazy loading

答案 1 :(得分:0)

因此,您的意思是,您拥有Employee,并且与FamilyMember之间有〜ToMany关系(被延迟获取)。您拥有遍历员工所有家庭成员的代码,对吗?

即像这样的东西:

class Employee {
    @OneToMany(fetch=LAZY)
    List<FamilyMember> familyMembers;
}

以及您的代码中

for (Employee employee: someEmployees) {
    for (FamilyMember member: employee.getFamilyMembrs()) {
        // do something
    }
}

类似的东西? (在您的代码示例中,因为Coz,您只是选择了FamilyMember,它与延迟获取无关)

在这种情况下,懒惰提取不会提高性能。

Lazy Fetch帮助提高性能的主要情况是,没有使用lazy-fetched关系。因此,当Hibernate构建实体时,它只是将代理作为关系,而无需实际检索相关实体,从而节省了数据库访问,数据传输和对象构造。

但是,在您的情况下,您需要访问该关系,因此Hibernate不会使您摆脱上述工作。而且,由于延迟获取是延迟完成的,这意味着将首先检索您的主要实体,然后在您访问它时检索该关系。与一次全部获取主要实体+关系的适当的join-fetch相比,它通常甚至更慢。


更新:对于您的其他问题:Hibernate如何在不先查询子记录的情况下处理这种惰性获取。这是高级别的事情:

首先,休眠对于不同类型的关系类型以不同的方式处理懒惰获取。在这种情况下,这是OneToMany关系。基于@OneToMany List<FamilyMember> familyMembers;的映射,Hibernate知道的是:

FamilyMember表(“多”面)将具有一列(默认情况下,其命名为EmployeeId),其中包含当前实体的ID(Employee, “一对一”一面)

因此,Hibernate将要创建的延迟获取代理是:集合代理在被访问时将使用SQL select * from FamilyMember where EmployeeId = :id进行查询,为此:id将被提供给当前实体ID。

这样做,在构造Employee时,您不需要查询其子记录(FamilyMember)的任何内容。

假设您执行employee.getFamilyMembers().get(2);,则.get(...)方法将触发延迟获取集合代理填充数据,这将获取所有相关的FamilyMember记录(相反, (仅第3个)。然后用数据填充集合,然后用第3个返回您。

要了解Hibernate的获取行为,我建议您打开Hibernate发出的SQL日志记录(通过诸如jdbcdslog或log4jdbc之类的工具),这样您就可以可视化Hibernate在什么情况下查询什么时间和查询什么。 / p>