java - Hibernate:n+1 且实体图性能缓慢

标签 java hibernate jpa

我们升级到 Hibernate 5,之后我们开始遇到性能问题。

我们有几个具有这样关联的实体:

@Entity
@Table(name = "EVENT")
public class Event {
    @Id
    @Column(name = "ID")
    private Long id;

    @ManyToOne(fetch = FetchType.EAGER)
    @JoinColumn(name = "LOCATION", referencedColumnName = "ID")
    private Location location;
}

@Entity
@Table(name = "LOCATION")
public class Location {
    @Id
    @Column(name = "ID")
    private Long id;
}

我们正在使用 Criteria API 从数据库中获取数据。

CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery<Event> query = cb.createQuery(Event.class);
Root<Event> from = query.from(Event.class);
query.select(from).where(from.get("id").in(1, 2, 3));
TypedQuery<Event> tQuery = entityManager.createQuery(query);
tQuery.setMaxResults(1000);
tQuery.getResultList();

以前(版本 4,旧 Criteria API),Hibernate 仅基于 FetchType.EAGER 生成一个带有获取所有数据的 join 语句的选择,但在 Hibernate 5 中,它会创建多个附加查询来获取“位置”数据 - N+1 问题。

现在,我们尝试了 JPA Entity Graph,结果好坏参半。我们能够减少查询次数(现在不再是 N+1),但另一方面,系统的性能甚至更慢。

我的问题是:

  1. 还有哪些其他方法可以解决 N+1 查询问题?
  2. 在什么情况下实体图会对性能产生负面影响?

(我们使用 SQL Server、Tomcat、Hibernate 5.2.10、Java 8。)

最佳答案

要获得在单个查询中获取位置数据并加入连接的早期行为,可以通过添加 fetch

来实现
from.fetch("location", javax.persistence.criteria.JoinType.LEFT);

所以你的代码看起来像:

CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery<Event> query = cb.createQuery(Event.class);
Root<Event> from = query.from(Event.class);
from.fetch("location", javax.persistence.criteria.JoinType.LEFT);
query.select(from).where(from.get("id").in(1, 2, 3));
TypedQuery<Event> tQuery = entityManager.createQuery(query);
tQuery.setMaxResults(1000);
tQuery.getResultList();

关于java - Hibernate:n+1 且实体图性能缓慢,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49282992/

相关文章:

java - 为静态使用加载位图对垃圾收集不利吗?

java - MongoDB 3 Java检查集合是否存在

javascript - 在 AngularJS 中处理多个异步调用和范围更新的最佳方法

java - 查询我的 JPA 提供程序 (Hibernate) 以获取实体的 <Id,Name> 集合

java - JPA NamedQuery 选择特定列并返回类类型

c# - 让你的集合线程安全?

java - JPA与同一实体的双重关系

java - 在 hibernate 中映射 PostgreSQL LTREE 列时出错

java - 在 MySQL 中使用数字创建序列日期

java - 如何使用 Selenium Webdriver 对下面提供的代码片段使用拖放功能