【问题标题】:Hibernate query executes more than expected timesHibernate 查询执行次数超过预期
【发布时间】:2013-08-25 11:43:22
【问题描述】:

我有下面提到的实体关系。当我运行我的应用程序时,我可以看到 Hibernate 生成的以下查询执行了 13 次(1+12),其中 12 是我在前端应用程序中显示的行数。理想情况下,它应该只执行一次,因为我不确定它为什么会执行 12 次。如果我将要在前端应用程序中显示的行数更改为 20,则查询将执行 21 次。

我该如何解决这个问题?

Hibernate 自动生成的查询

select employee0_.EMPLOYEE_NUMBER as EMP1_2_0_, employee0_.DEPARTMENT_CODE as  
DEPARTMENT3_2_0_, employee0_.EMPLOYEE_DEPT as EMPLOYEE4_2_0_, employee0_.DESIGNATION
as DESIGNAT5_2_0_, employee0_.EMPLOYEE_NAME as EMPLOYEE6_2_0_  from EMPLOYEES 
employee0_ where employee0_.EMPLOYEE_NUMBER=?

实体类

   @Entity
   public class Project
   @ManyToOne
   @JoinColumn(name = "EMPLOYEE_NUMBER", referencedColumnName = "EMPLOYEE_NUMBER")
   private Employee requester;

   @ManyToOne
   @JoinColumn(name = "APPROVER", referencedColumnName = "EMPLOYEE_NUMBER")
   private Employee approver;
   }

   @Entity
   public class Employee {
   @OneToMany(mappedBy = "requester")
   private Set<Project> requestedProjects;

   @OneToMany(mappedBy = "approver")
   private Set<Project> approvedProjects;
   }

JSF UI 源代码

<p:dataTable id="dataTable" var="proj" lazy="true"
    value="#{projMB.lazyModel}" styleClass="projTableStyle"
    paginator="true" paginatorPosition="bottom" rows="12"
    rowKey="#{proj.projectId}">
    <f:facet name="header">         

    <p:column id="employeeNo" headerText="Employee Name" width="16">
    <h:outputText value="#{proj.empNumber.employeeName}" />
    </p:column>
        .....
        .....

DAOImpl 类用于检索记录

CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery<Project> c = cb.createQuery(Project.class);
Root<Project> emp = c.from(Project.class);
c.orderBy(cb.desc(emp.get("projectId")));
c.select(emp);

CriteriaQuery<Long> countQ = cb.createQuery(Long.class);
Root<Project> empCount = countQ.from(Project.class);
countQ.select(cb.count(empCount));

List<Predicate> criteria = new ArrayList<Predicate>();
if (projectId != null) {
ParameterExpression<String> pexp = cb.parameter(String.class,
 "projectId");
Predicate predicate = cb.equal(emp.get(Project_.projectId), pexp);
criteria.add(predicate);
            }

TypedQuery<Project> q =  entityManager.createQuery(c);

控制器类

private List<Project> project = new ArrayList<Project>();
project = myservice.getDAOValues();
....

表格显示如下

Employee No, Employee Name, Project Id, Project Start Date 

编辑 2

@ManyToOne
@JoinColumn(name = "REQUESTOR", referencedColumnName = "EMPLOYEE_NUMBER", 
insertable = false, updatable = false)
private RequesterDepartment requesterDepartment;

【问题讨论】:

  • 您在 UI 中显示什么?您如何获取要显示的信息?
  • @JBNizet 我正在使用 JSF Primefaces,并且在我的问题中包含了我的 JSF 代码,如果遗漏了您询问的任何信息,请告诉我。谢谢
  • 我不知道 Primefaces。您在控制器中获得的数据是什么,您如何获得它,即您正在执行哪个 JPQL/标准查询?表格显示了什么?
  • 如果我没记错的话,你可以避免使用 fetch join 或 fetch subselect 的 n+1 行为:docs.jboss.org/hibernate/core/3.3/reference/en/html/…
  • @JBNizet 我更新了问题,其中包含来自 DAOImpl、控制器类的代码 sn-ps 的详细信息。谢谢

标签: hibernate jpa jpa-2.0


【解决方案1】:

您希望在单个查询中加载项目及其各自的请求者或批准者。这是使用 fetch join 完成的。在 JPQL 中:

select p from Project p
left join fetch p.requester
where ...

在 Criteria 中,有一个等价的结构:

Root<Project> project = c.from(Project.class);
project.fetch(Project_.requester, JoinType.LEFT);

请注意,我将 emp 重命名为 projectemp 几乎可以作为 Employee 路径的名称。将它用于Project 路径非常令人困惑。

【讨论】:

  • 如果我没有project.fetch(Project_.requester, JoinType.LEFT);,那么查询会执行多次,这是否会导致任何性能问题,或者这是一个好习惯吗?谢谢
  • 是的,它会导致性能问题。如果这个问题没有任何重大影响,那么您可以选择不关心它。但我会做 fetch join。
  • 感谢您的帮助,不胜感激。
  • 我对使用 fetch join 有另一个疑问。我已将问题编辑为 Edit 2,并将 requestor 属性与另一个名为 RequesterDepartment 的类的另一个映射进行了编辑,以获取 requestor 所属部门的名称。在这种情况下,我如何参考 Criteria 中的RequesterDepartment 类来使用 JoinType 来获取请求者部门?谢谢
猜你喜欢
  • 2023-01-31
  • 1970-01-01
  • 1970-01-01
  • 2019-10-14
  • 1970-01-01
  • 1970-01-01
  • 2016-04-07
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多