为什么 Hibernate (JPA) 忽略 ManyToOne 关系的 FetchType.LAZY?
Why does Hibernate (JPA) ignore FetchType.LAZY for ManyToOne relations?
我有这个实体,我想要一个延迟加载的多对一关系。
@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();
从休眠日志的倒数第二行我可以看到发出第二个 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,它就不应该从数据库中加载。
知道为什么休眠会初始化代理吗?
这是对问题的精简解释。实际上,我在产品上有很多多对一的关系。他们都被宣布为惰性。但由于它们实际上加载得很慢,我得到了很大的 select N+1 性能损失。
经过大量搜索,我最终在生成日志语句 Initializing proxy:
的 org.hibernate.internal.SessionImpl
中设置了一个断点。在堆栈跟踪中,我终于在 Product
:
中找到了这个
@PostLoad
public void postLoad() {
atcCode.getCode();
}
这会导致休眠初始化代理。
我有这个实体,我想要一个延迟加载的多对一关系。
@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();
从休眠日志的倒数第二行我可以看到发出第二个 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,它就不应该从数据库中加载。
知道为什么休眠会初始化代理吗?
这是对问题的精简解释。实际上,我在产品上有很多多对一的关系。他们都被宣布为惰性。但由于它们实际上加载得很慢,我得到了很大的 select N+1 性能损失。
经过大量搜索,我最终在生成日志语句 Initializing proxy:
的 org.hibernate.internal.SessionImpl
中设置了一个断点。在堆栈跟踪中,我终于在 Product
:
@PostLoad
public void postLoad() {
atcCode.getCode();
}
这会导致休眠初始化代理。