Hibernate n + 1选择多个表层次结构

时间:2016-06-23 15:53:00

标签: java hibernate jpa fetch jpql

我有下一个班级结构

@Entity
@Table(name = "Company")
public class Company {
   @Id
   @GeneratedValue
   private Long id;

   @OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true)
   @JoinColumn(name = "CompanyId")
   @Fetch(FetchMode.SUBSELECT)
   private Set<Departement> departements;
}

@Entity
@Table(name = "Departement")
public class Departement {
   @Id
   @GeneratedValue
   private Long id;

   @OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true)
   @JoinColumn(name = "DepartementId")
   @Fetch(FetchMode.SUBSELECT)
   private Set<Employee> employees;
}

@Entity
@Table(name = "Employee")
public class Employee {
   @Id
   @GeneratedValue
   private Long id;

  // other fields and methods
}

在应用程序启动时,我需要使用已初始化的内部集合来获取所有公司。我的数据库足够大(公司表中有1,5 M行)。我需要解决n + 1选择问题以加速数据检索。带有提取连接的解决方案在我的情况下不起作用,因为生成的sql查询返回了大量的数据集,即使我像这样使用滚动

Query query = session.createQuery(query);
query.setReadOnly(true);
// MIN_VALUE gives hint to JDBC driver to stream results
query.setFetchSize(Integer.MIN_VALUE);
ScrollableResults results = query.scroll(ScrollMode.FORWARD_ONLY);

它仍然消耗我的所有RAM,因为我无法刷新会话或驱逐检索到的实体。

另一种方法是使用子选择,但是当我这样做时

@SuppressWarnings("unchecked")
List<Company> companies = session.createQuery("from Company").list();

for (Company c : companies) {
    for (Departement d : c.getDepartements()) {
        d.getEmployees();
    }
}

hibernate只生成2个查询:一个用于公司表

select ... from Company company

和另一个部门表

select ... from Departement departemen0_ 
where departemen0_.CompanyId in (select company0_.id from Company company0_)

我仍然需要分别从Departement类初始化员工集合。

有没有办法用子选择检索所有3个表?或者可能有另一种方法来检索给定结构的大量数据?

1 个答案:

答案 0 :(得分:0)

您的代码仅生成两个查询(针对公司和部门),因为您的员工查询代码(第三个也是所需的)没有被延迟获取。因此,只需更改:

d.getEmployees();

收件人:

d.getEmployees().size();

如果您要处理的数据量如此,SUBSELECT似乎是best strategy的理想之选:

  
      
  • JOIN:避免了主要的N + 1查询问题,但它可以检索重复的数据。
  •   
  • SUBSELECT:也避免N + 1并且不重复数据,但是它将所有关联类型的实体加载到内存中。
  •