【发布时间】:2016-10-26 01:42:04
【问题描述】:
我有下一个班级结构
@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
}
在应用程序启动时,我需要获取所有具有初始化内部集合的公司。我的数据库足够大(Company 表中有 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 个查询:一个用于 Company 表
select ... from Company company
另一个用于部门表
select ... from Departement departemen0_
where departemen0_.CompanyId in (select company0_.id from Company company0_)
我仍然需要分别从部门类初始化员工集合。
有没有办法用子选择检索所有 3 个表?或者可能有另一种方法来检索具有给定结构的大量数据?
【问题讨论】:
-
通常你在类的顶部添加
@NamedEntityGraph(name = "Company.withDepartment", attributeNodes = @NamedAttributeNode("department"))Company和@NamedEntityGraph(name = "Department.withEmployee", attributeNodes = @NamedAttributeNode("employee"))在类的顶部下方Department。 -
然后您将以下代码添加到您的命名查询(更好地使用命名查询):
{yourEntityManager}.{yourNamedQuery}.setHint("javax.persistence.loadgraph", getEntityManager().createEntityGraph("Company.withDepartment")) .getResultList();和{yourEntityManager}.{yourNamedQuery}.setHint("javax.persistence.loadgraph", getEntityManager().createEntityGraph("Department.withEmployee")) .getResultList(); -
- 对于
id,我会使用简单的long而不是Long。 -
- 对于
departments,我会写:@OneToMany @JoinColumn(name = "companyId") private Set<Departement> departements; -
- 对于
employees,我会写@OneToMany @JoinColumn(name = "departementId") private Set<Employee> employees;
标签: java hibernate jpa fetch jpql