2014-03-06 61 views
5

实现一对多关系,工作正常。JPA一对多关系查询

我的问题是当我运行下面的查询,如果该表有100个员工行,并且每个员工有2个部门。数据库查询被称为101次,因为对于每个员工来说都是调用部门查询,完成调用所有的100行花费很长时间,任何人都可以提出任何替代解决方案吗?

请参考下面

查询详情它呼吁:

First query is : SELECT * FROM Employee e 

    Next 100 queries : SELECT * FROM DEPARTMENT d WHERE d.EmployeeId=? 

JPA数据库调用:

javax.persistence.Query query = em.createNamedQuery("SELECT * FROM Employee e", Employee.class); 

    return query.getResultList(); 




    import javax.persistence.CascadeType; 
    import javax.persistence.Column; 
    import javax.persistence.Entity; 
    import javax.persistence.FetchType; 
    import javax.persistence.Id; 
    import javax.persistence.NamedNativeQueries; 
    import javax.persistence.NamedNativeQuery; 
    import javax.persistence.OneToMany; 
    import javax.persistence.Table; 

    @Entity 
    @Table(name = "EMPLOYEE") 
    public class Employee implements Serializable 
    { 
     @Id 
     @Column(name = "EmployeeId") 
     String employeeId; 

     @OneToMany(mappedBy = "employee", cascade = CascadeType.ALL, fetch = FetchType.EAGER) 
     private List<Department> departments; 

     public List<Department> getDepartments() { 
      return departments; 
     } 

     public void setDepartments(List<Department> departments) { 
      this.departments = departments; 
     } 

     public String getEmployeeId() { 
      return employeeId; 
     } 

     public void setEmployeeId(String employeeId) { 
      this.employeeId = employeeId; 
     } 
    } 

    @Entity 
    @Table(name = "DEPARTMENT") 
    public class Department implements Serializable 
    { 
     private static final long serialVersionUID = 1L; 

     @Id 
     @Column(name = "DepartmentID") 
     String departmentId; 

     @ManyToOne(fetch = FetchType.EAGER) 
     @JoinColumn(name = "EmployeeId", insertable = false, updatable = false) 
     private Employee employee; 
    } 

输出XML:

 <Employees> 
      <Employee> 
       <name>Rob</name> 
       <Departments> 
        <Departmnet><id>1</id></Departmnet> 
        <Departmnet><id>2</id></Departmnet> 
       </Departments> 
      </Employee> 
      <Employee> 
       <name>Sam</name> 
       <Departments> 
        <Departmnet><id>1</id></Departmnet> 
        <Departmnet><id>2</id></Departmnet> 
       </Departments> 
      </Employee> 
     </Employees> 
+0

你为什么不使用联接 –

+1

@PhilippSander:你可能指的是抓取连接?毕竟这是JPA,持久性提供者会为你加入。 – Gimby

回答

4

这是一个典型的N+1 selects issue前循环的employee.getDepartmentList()例如

for(Department dept:employeeGetDepartmentList()){ 
dept.getId(); 
} 

。我通常用JOIN FETCH来解决这个问题described herehere

1

你可以切换fetc htype转为懒惰,这将导致部门只在必要时被查询。

@OneToMany(mappedBy = "employee", cascade = CascadeType.ALL, fetch = FetchType.LAZY) 
private List<Department> departments; 
+0

实际上,这是oneToMany映射的默认获取类型,所以它实际上是一种不试图覆盖JPA API设计者认为是个好主意的行为:) – Gimby

+0

嗨,感谢您的回答,我也使用了懒惰,但是仍然加载100个查询。我主要想要替代我已经实施的。 – user3157090

1

FetchType.EAGER更改为FetchType.LAZY。只加载部门当你需要他们这是使用部门

+1

嗨谢谢你的回答,我也用过懒惰,但仍然加载100个查询。我主要想要替代我已经实施的。 – user3157090

1

经典N + 1问题。 您可以减少批量查询的数量,它只是将许多懒惰的SQL子句组合为单个查询。

例如:

@OneToMany(mappedBy = "employee", cascade = CascadeType.ALL, fetch = FetchType.LAZY) 
@BatchSize(size=10) 
private List<Department> departments;