JPA一对多关系查询

5

已经实现了一对多关系,目前运行良好。

我的问题是当我运行以下查询时,如果表中有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>

为什么不使用连接(joins)? - Philipp Sander
1
@PhilippSander: 你也许指的是一个 fetch join 吗?毕竟这是 JPA,持久化提供程序会为您执行联接。 - Gimby
4个回答

4

2
您可以将fetchtype切换为lazy,这将导致只在必要时查询部门。
@OneToMany(mappedBy = "employee", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
private List<Department> departments;

实际上,这是oneToMany映射的默认获取类型,因此不尝试覆盖JPA API设计者认为是一个好主意的行为 :) - Gimby
你好,感谢你的回答。我已经使用了lazy,但仍然加载了100个查询。我主要想寻找我所实现的替代方案。 - user3157090

2

FetchType.EAGER更改为FetchType.LAZY。仅在需要时加载部门,例如循环遍历employee.getDepartmentList()

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

在使用部门之前


1
你好,感谢你的回答。我已经使用了lazy,但仍然加载了100个查询。我主要想寻找我所实现的替代方案。 - user3157090

2
经典的N+1问题。 您可以通过批量获取来减少查询次数,它将许多懒惰SQL子句组合成单个子句。
例如:
@OneToMany(mappedBy = "employee", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
@BatchSize(size=10)
private List<Department> departments;

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接