gpt4 book ai didi

java - JPA 和 Hibernate 中的 N+1 问题的解决方案是什么?

转载 作者:IT老高 更新时间:2023-10-28 21:13:56 25 4
gpt4 key购买 nike

我知道 N+1 问题是执行一个查询以获取 N 条记录,执行 N 个查询以获取一些关系记录。

但是在 Hibernate 中如何避免呢?

最佳答案

问题

当您忘记获取关联然后您需要访问它时,会发生 N+1 查询问题。

例如,假设我们有以下 JPA 查询:

List<PostComment> comments = entityManager.createQuery("""
select pc
from PostComment pc
where pc.review = :review
""", PostComment.class)
.setParameter("review", review)
.getResultList();

现在,如果我们迭代 PostComment 实体并遍历 post 关联:

for(PostComment comment : comments) {
LOGGER.info("The post title is '{}'", comment.getPost().getTitle());
}

Hibernate 会生成以下 SQL 语句:

SELECT pc.id AS id1_1_, pc.post_id AS post_id3_1_, pc.review AS review2_1_
FROM post_comment pc
WHERE pc.review = 'Excellent!'

INFO - Loaded 3 comments

SELECT pc.id AS id1_0_0_, pc.title AS title2_0_0_
FROM post pc
WHERE pc.id = 1

INFO - The post title is 'Post nr. 1'

SELECT pc.id AS id1_0_0_, pc.title AS title2_0_0_
FROM post pc
WHERE pc.id = 2

INFO - The post title is 'Post nr. 2'

SELECT pc.id AS id1_0_0_, pc.title AS title2_0_0_
FROM post pc
WHERE pc.id = 3

INFO - The post title is 'Post nr. 3'

N+1 查询问题就是这样产生的。

因为在获取 PostComment 实体时 post 关联没有初始化,所以 Hibernate 必须使用辅助查询获取 Post 实体,并且对于N 个 PostComment 实体,还有 N 个查询将被执行(因此出现 N+1 个查询问题)。

修复

解决此问题需要做的第一件事是添加[正确的 SQL 日志记录和监控][1]。如果没有日志记录,您在开发某个功能时不会注意到 N+1 查询问题。

其次,要修复它,您只需 JOIN FETCH 导致此问题的关系:

List<PostComment> comments = entityManager.createQuery("""
select pc
from PostComment pc
join fetch pc.post p
where pc.review = :review
""", PostComment.class)
.setParameter("review", review)
.getResultList();

如果您需要获取多个子关联,最好在初始查询中获取一个集合,然后在辅助 SQL 查询中获取第二个集合。

如何自动检测N+1查询问题

这个问题最好通过集成测试来发现。

您可以使用自动 JUnit 断言来验证生成的 SQL 语句的预期计数。 db-util project已经提供了这个功能,并且它是开源的,并且依赖项在 Maven Central 上可用。

关于java - JPA 和 Hibernate 中的 N+1 问题的解决方案是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32453989/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com