hibernate - JPA Hibernate n+1 问题(Lazy & Eager Diff)

标签 hibernate spring-data-jpa

我试图理解 n+1 问题,从而找到正确的解决方法。

我有两个实体:
公司

@Entity
@Table(name="company")
public class Company implements Serializable {

    private static final long serialVersionUID = 1L;


    @Id
    @GeneratedValue
    private int id;

    @Column(name="cmp_id")
    private int cmpId;

    @Column(name="company_name")
    private String companyName;

    @OneToMany(fetch=FetchType.LAZY)
    @JoinColumn(name="cmp_id",referencedColumnName="cmp_id")
    private Set<Employee> employee;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public int getCmpId() {
        return cmpId;
    }

    public void setCmpId(int cmpId) {
        this.cmpId = cmpId;
    }

    public String getCompanyName() {
        return companyName;
    }

    public void setCompanyName(String companyName) {
        this.companyName = companyName;
    }

    public Set<Employee> getEmployee() {
        return employee;
    }

    public void setEmployee(Set<Employee> employee) {
        this.employee = employee;
    }



}

员工
@Entity
@Table(name="employee")
public class Employee implements Serializable {

    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue
    private int id;

    @Column(name="emp_id")
    private int empId;

    @Column(name="emp_name")
    private String empName;

    /*@ManyToOne(fetch=FetchType.LAZY)
    @JoinColumn(name="cmp_id", referencedColumnName="cmp_id")
    @JsonIgnore
    private Company company;*/

    @Column(name="cmp_id")
    private int cmpId;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public int getEmpId() {
        return empId;
    }

    public void setEmpId(int empId) {
        this.empId = empId;
    }

    public String getEmpName() {
        return empName;
    }

    public void setEmpName(String empName) {
        this.empName = empName;
    }

}

每个公司都有很多员工。如此简单的单向一对多关系。
现在,当我运行查询(“从公司 a 中选择一个”)时,我面临 n+1 个选择(当我试图获得员工时)

但是为了更清楚地理解这些概念,当我将其更改为 EAGER 时,所有相同的 n+1 查询最初都在运行(即使我没有获取员工)。这是正确的行为吗?我的意思是它不应该触发连接查询。另外,如何使用 EAGER 更改代码以仅产生 1 个查询。?

最佳答案

“问题”并不是真正的问题,而是关于 ORM 的工作方式。 Hibernate 创建了所谓的 nested queries如果您访问这样的协会。

你是对的,在这两种情况下都执行相同的查询,切换 FetchType您的映射来自 LAZYEAGER仅调度附加 (n+1) 查询的执行。

假设你有很多公司,他们都有员工,在这两种情况下,这样的查询都会被执行(至少一次):

select ... from company company0_

select ... from employee employee0_ where employee0_.cmp_id=?

执行第一个以获取所有公司,第二个执行每个公司一次。

例如:3 家公司 (N) 和许多员工将执行第一次选择一次,三个嵌套选择 = 3+1 = 4 次查询。
EAGER的区别和 LAZY就在时间点上,您通常无法避免数据库访问,因为您仍然需要数据。与 LAZY附加查询只是推迟到您迭代员工集合。但请记住,这只是一个提示,并非每个数据库驱动程序都支持延迟加载。

如果你真的知道你总是需要数据,你可以写一个 FETCH JOIN一键查询和接收所有需要的数据:
Select c from Company c JOIN FETCH c.employee e

这将执行如下查询:
select ... from company company0_ inner join employee employee1_ on company0_.cmp_id=employee1_.cmp_id

这将避免第二次数据库访问。为了在您的测试中验证这一点,也许 the datasource proxy project是给你的东西。

关于hibernate - JPA Hibernate n+1 问题(Lazy & Eager Diff),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43513449/

相关文章:

hibernate - 如何使用 spring-jpa 创建复合键,其中键的一个属性在 @MappedSuperClass 中,而其他属性在 @Entity 类中?

java - Spring Boot中的分页循环关联数据

java - 有哪些与 java、spring、hibernate、maven 相关的好博客值得阅读?

java - Hibernate实体没有PK但有FK

java - 使用参数指定命名查询中的表达式

java - 在 Spring data JPA 中将字符串转换为 CLOB

java - Spring数据存储库在测试用例类中未使用@Mock注入(inject)返回null?

java - 在 hibernate 中延迟加载子项时使用 print 语句

java - Hibernate/JPA 注释中的多列连接

java - 如何在 Spring 中使用 JPA 存储库从服务器检索 blob