【问题标题】:JPA one to many relationship queryJPA 一对多关系查询
【发布时间】:2014-04-08 21:12:18
【问题描述】:

实现了一对多关系,并且运行良好。

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

请看下面的详细信息

它正在调用的查询:

    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>

【问题讨论】:

  • 你为什么不使用连接
  • @PhilippSander:您可能指的是 fetch join 吗?这毕竟是 JPA,持久化提供者会为你加入。

标签: java sql hibernate jpa


【解决方案1】:

这是一个典型的N+1 selects issue。我通常用JOIN FETCH 查询described herehere 来解决这个问题

【讨论】:

    【解决方案2】:

    您可以将 fetchtype 切换为惰性,这将导致仅在必要时查询部门。

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

    【讨论】:

    • 实际上这是 oneToMany 映射的默认获取类型,因此它实际上是一种不尝试覆盖 JPA API 设计人员认为的好主意的行为 :)
    • 您好,谢谢您的回答,我也使用了lazy,但仍会加载100个查询。我主要想要替代我已实施的内容。
    【解决方案3】:

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

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

    在使用部门之前

    【讨论】:

    • 您好,谢谢您的回答,我也使用了lazy,但仍会加载100个查询。我主要想要替代我已实施的内容。
    【解决方案4】:

    经典的 N+1 问题。 您可以使用批量提取来减少查询数量,它只是将许多惰性 sql 子句组合成一个。

    例如:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-08-19
      • 1970-01-01
      • 1970-01-01
      • 2013-11-18
      • 1970-01-01
      • 2017-10-28
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多