Hibernate @LazyCollection注解的作用是什么?

40

我有两个实体,一个是父实体,另一个是子实体,它们之间的关系是一对多。

@Entity
public class Parent {

@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;

private String name;

@OneToMany(mappedBy = "parent", fetch = FetchType.LAZY)
@IndexColumn(name = "index", base = 1)
@Cascade(org.hibernate.annotations.CascadeType.ALL)
@LazyCollection(LazyCollectionOption.EXTRA)
private List<Child> childs = new ArrayList<Child>();
// getter and setter

}

这里的@LazyCollection(LazyCollectionOption.EXTRA)有什么用途?在哪些操作中使用子列表时,它会发挥作用并带来好处?

3个回答

45

EXTRA = .size() 和 .contains() 不会初始化整个集合

TRUE = 首次访问时初始化整个集合

FALSE = 急切加载(Eager-Loading)


.get(0) 会初始化整个集合吗? - lakshayg
1
@LakshayGarg 是的 - wutzebaer
@LakshayGarg,这取决于你使用的选项,EXTRA不会初始化整个集合,而是会执行此特定元素的查询。但是,如果你使用附加到该集合的迭代器,例如在流或for each循环中,则会初始化它。TRUE - 将始终初始化整个集合。 - Voland Mortes

29

实际上没有理由使用@LazyCollection

TRUEFALSE的值不是必需的,因为可以通过JPA FetchType.LAZYFetchType.EAGER获得相同的行为。

EXTRA值在JPA中没有等价物,它是为非常大的集合设计的。当您第一次访问一个EXTRA懒惰集合时,集合并不会完全加载,就像任何JPA集合通常情况下一样。

相反,每个元素都会逐个获取,使用二次SELECT。虽然这听起来像是一种优化,但实际上不是,因为EXTRA懒惰集合容易出现N+1查询问题。

请注意,这仅适用于有序集合,即用@OrderColumnMap注释的ListMap。对于无序集合(例如不保留任何特定顺序的常规List),@LazyCollection(LazyCollectionOption.EXTRA)的行为与任何其他LAZY集合一样(在第一次访问集合时会完全获取集合)。

如果您有一个非常大的集合,那么您根本不应该映射它。相反,您应该仅映射@ManyToOne一侧,并且您应该使用分页JPQL查询而不是父级集合。

因为您可以应用任何过滤条件并且可以对结果集进行分页,所以JPQL查询要容易得多。


1
我可以问一下什么被认为是非常大的集合吗? - Uri Loya
1
一个非常大的集合是指从数据库中获取需要花费相当长时间的集合。 - Vlad Mihalcea
2
在你的回答和文章中,你做了一个假设,即集合中的项将被迭代。但这并不总是正确的。我们有一些例子,我们只想在集合上使用.size()。使用@LazyCollection( LazyCollectionOption.EXTRA ),这就是一个简单的SELECT COUNT(id) FROM..。如果没有LazyCollectionOption,操作将变成:选择所有匹配的行,将它们映射到对象中,然后计算对象的数量。在我运行的简单测试中,对于一个包含50,000个项目的集合,这可能会导致1或2秒的差异。 - Bernie
1
你假设映射集合是一项职责。只有当集合的大小相对较小时,才值得映射集合。对于大型集合,请使用查询进行分页。对于集合大小,只需使用COUNT查询即可。它非常有效。 - Vlad Mihalcea
1
@VladMihalcea,所以你的论点归结为“这个特性很糟糕,因为有人可能会错误地使用它并遇到性能问题”。我认为这不是评估一个特性有用性的好标准,并建议你,Hibernate(和许多其他库[以及Java和其他语言])中有许多具有相同缺陷的功能(如果你认为这样的属性是一个缺陷)。 - Bernie
显示剩余5条评论

9

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接