为什么Hibernate(JPA)在ManyToOne关系中忽略FetchType.LAZY?

4

我有一个实体,希望在加载时能够实现多对一的懒加载关系。

@Entity
public class Product {
    @ManyToOne(fetch=FetchType.LAZY)
    @JoinColumn(name = "atc_code_id")
    private ATCCode atcCode;
}

@Entity
public class ATCCode {
    @OneToMany(mappedBy = "atcCode")
    private Set<Product> products;
}

我正在使用以下代码来加载产品:

Query q = entityManager.createQuery("select p from Product as p");
List<Product> products = q.getResultList();

从Hibernate日志的倒数第二行可以看到,发出了第二个select语句来初始化atcCode代理。为什么会这样呢?

17925 07 Aug 2015 11:45:20 SQL DEBUG 352066 kb - select product0_.id ...
17926 07 Aug 2015 11:45:20 Loader DEBUG 348515 kb - Result set row: 0
17927 07 Aug 2015 11:45:20 Loader DEBUG 348515 kb - Result row: EntityKey[com.galexis.search.importer.search.searchdb.model.Product#1]
17928 07 Aug 2015 11:45:20 Loader DEBUG 348515 kb - Result set row: 1
17929 07 Aug 2015 11:45:20 Loader DEBUG 348515 kb - Result row: EntityKey[com.galexis.search.importer.search.searchdb.model.Product#2]
17929 07 Aug 2015 11:45:20 TwoPhaseLoad DEBUG 348515 kb - Resolving associations for [com.galexis.search.importer.search.searchdb.model.Product#1]
17931 07 Aug 2015 11:45:20 TwoPhaseLoad DEBUG 348515 kb - Done materializing entity [com.galexis.search.importer.search.searchdb.model.Product#1]
17931 07 Aug 2015 11:45:20 TwoPhaseLoad DEBUG 348515 kb - Resolving associations for [com.galexis.search.importer.search.searchdb.model.Product#2]
17931 07 Aug 2015 11:45:20 TwoPhaseLoad DEBUG 348515 kb - Done materializing entity [com.galexis.search.importer.search.searchdb.model.Product#2]
17931 07 Aug 2015 11:45:20 SessionImpl DEBUG 348515 kb - Initializing proxy: [com.galexis.search.importer.search.searchdb.model.ATCCode#100]
17931 07 Aug 2015 11:45:20 SQL DEBUG 348515 kb - select atccode0_.id  ...

我希望返回一个代理以替代atcCode。只要我不访问atcCode,它就不应该从数据库中加载。

你有任何想法为什么Hibernate会初始化代理对象吗?

这是问题的简化版本。实际上,我的产品(product)有很多多对一(many-to-one)关系,它们都被声明为懒加载(lazy)。但由于它们实际上被急加载了(eagerly),所以我会遭受到大量的N+1查询性能损失。

1个回答

0
经过大量搜索,我最终在org.hibernate.internal.SessionImpl中设置了一个断点,其中生成了日志语句Initializing proxy:。通过上溯堆栈跟踪,我最终在Product中找到了这个问题。
@PostLoad
public void postLoad() {
    atcCode.getCode();
}

这会导致Hibernate初始化代理。


这回答了你的问题吗?你还在努力让延迟加载正常工作,对吧? - Kai
1
它完美地回答了这个问题。postLoad 渲染了延迟加载声明的无效,因为它强制 hibernate 初始化代理。 - BetaRide
好的...我只是想让你知道如何抑制那个调用。 - Kai
不幸的是,我认为这个答案对于那些遇到这个问题的人来说是一个相当边缘情况的少数派。 - Alkanshel
我也遇到了同样的问题,我该如何抑制这个调用? - Darlyn

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