【问题标题】:ManyToOne Always Running Queries(always eager)多对一总是运行查询(总是急切)
【发布时间】:2017-04-21 06:08:39
【问题描述】:

您好,我正在使用 Spring Data JPA (hibernate) 和 spring boot。

我有两个实体类

公司-----> 员工 与每家公司的双向关系有多个员工。(从公司到员工的一对一)

公司实体

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, mappedBy="company")
    private Set<Employee> employee;

    ... Getters & Setters   

}

员工实体

@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;

    .... Getters & Setters ...
}

公司服务

public class CompanyService {

    @Autowired
    private CompanyRepository companyRepo;

    public Company fetchCompany(int cmpId){
        return companyRepo.findByCmpId(cmpId);
    }
}

公司回购

public interface CompanyRepository extends JpaRepository<Company, Integer>{ 
    public Company findByCmpId(int cmpId);
}

API 代码(调用服务方法)

@RequestMapping("/cmp/{cmpId}")
    public void findCmp(@PathVariable int cmpId){
        Company cmp = cmpService.fetchCompany(cmpId);
        System.out.println(cmp.getCompanyName());
        Set<Employee> ee = cmp.getEmployee();
        for(Employee e : ee){
            System.out.println(e.getEmpName());
        }
    }

现在这个 api 代码触发了 5 个查询..

Hibernate: select company0_.id as id1_1_, company0_.cmp_id as cmp_id2_1_, company0_.company_name as company_3_1_ from company company0_ where company0_.cmp_id=?
Hibernate: select employee0_.cmp_id as cmp_id4_2_0_, employee0_.id as id1_2_0_, employee0_.id as id1_2_1_, employee0_.cmp_id as cmp_id4_2_1_, employee0_.emp_id as emp_id2_2_1_, employee0_.emp_name as emp_name3_2_1_ from employee employee0_ where employee0_.cmp_id=?
Hibernate: select company0_.id as id1_1_0_, company0_.cmp_id as cmp_id2_1_0_, company0_.company_name as company_3_1_0_ from company company0_ where company0_.cmp_id=?
Hibernate: select company0_.id as id1_1_0_, company0_.cmp_id as cmp_id2_1_0_, company0_.company_name as company_3_1_0_ from company company0_ where company0_.cmp_id=?
Hibernate: select company0_.id as id1_1_0_, company0_.cmp_id as cmp_id2_1_0_, company0_.company_name as company_3_1_0_ from company company0_ where company0_.cmp_id=?

最后 3 个查询是多方连接的结果。虽然我已经提到它很懒,但它仍然很热心。如何更改我的代码以使其变得懒惰(基本上我需要停止触发这 3 个查询)。

【问题讨论】:

    标签: spring-boot spring-data spring-data-jpa


    【解决方案1】:

    这似乎不可取,但惰性会按需加载实体。请注释掉,

      Set<Employee> ee = cmp.getEmployee();
      for(Employee e : ee){
           System.out.println(e.getEmpName());
      }
    

    并检查员工是否仍然急切地加载。我认为这是日志的原因

    【讨论】:

    • 如果我注释掉它可以正常工作,但如果需要员工姓名怎么办?
    • @AnkitBansal 正如 Lazy 所暗示的,它按需获取。如果你调用 cmp.getEmployee()。然后它会引入员工,这就是你需要的,除非你得到员工,否则你无法得到员工的名字。您还可以根据公司 ID 编写另一种方法来获取员工 :)。
    • 我要问的是,既然懒惰的按需获取,员工到公司是懒惰的,那么为什么在我做 getEmpName() 时最后 3 个查询被触发。它应该只触发一名员工查询吗?不是吗?
    • No 调用 cmp.getEmployee() 时会获取所有相关员工。如果您想获得一名特定的员工。在 JpaRepository 接口中编写特定的@query 方法
    • 顺便说一句,我让你注释掉代码,只是为了让你理解它,寻找@Query以获得更多信息,否则你的代码会按照要求做
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-02-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多