为什么 Hibernate 在使用 @ManyToOne(fetch = FetchType.EAGER) 时执行两个而不是一个 SELECT 查询

问题描述 投票:0回答:1

我有以下实体

@Builder
@Getter @Setter
@NoArgsConstructor
@AllArgsConstructor
@Entity(name = "Employee")
@Table(schema = "core", name = "employee")
public class EmployeeEntity {

    @Id
    @SequenceGenerator(schema = "core", name = Sequence.EMPLOYEE_ID_SEQ, sequenceName = Sequence.EMPLOYEE_ID_SEQ)
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = Sequence.EMPLOYEE_ID_SEQ)
    @Column(name = "id", nullable = false, updatable = false)
    private Integer id;

    @Column(name = "person_id", nullable = false)
    private Integer personId;

    @Column(name = "user_account_id")
    private Integer userAccountId;

    @Column(name = "employee_type_id", nullable = false)
    private Integer employeeTypeId;

    @OneToOne(fetch = FetchType.EAGER)
    @JoinColumn(name = "person_id", insertable = false, updatable = false)
    private PersonEntity person;

    @ManyToOne(fetch = FetchType.EAGER, targetEntity = EmployeeTypeEntity.class)
    @JoinColumn(name = "employee_type_id", insertable = false, updatable = false)
    private EmployeeTypeEntity employeeType;

}

@Builder
@Getter @Setter
@NoArgsConstructor
@AllArgsConstructor
@Entity(name = "EmployeeType")
@Table(schema = "type", name = "employee_type")
@Cacheable @Cache(usage = CacheConcurrencyStrategy.READ_ONLY)
public class EmployeeTypeEntity implements TypeTable {

    @Id
    @Column(name = "id", nullable = false, updatable = false)
    private Integer id;

    @Column(name = "name", length = 100, nullable = false)
    private String name;

    @Column(name = "abbreviation", length = 10)
    private String abbreviation;

    @Column(name = "description", length = 100)
    private String description;

    @Builder.Default
    @Enumerated(EnumType.STRING)
    @Column(name = "active", length = 1, nullable = false)
    private Active active = Active.Y;

    @OneToMany(fetch = FetchType.LAZY, mappedBy = "employeeType", targetEntity = EmployeeEntity.class)
    private List<EmployeeEntity> employees;
}

我在 Quarkus 中使用 JPA Hibernate 并使用以下方法

    @Override
    public Pageable<EmployeeEntity> findAll(PageRequest request) {
        var query = employeePanacheRepository.findAll(
                        Sort.by(request.getSortBy(), Direction.valueOf(request.getSortDirection()))
                )
                .page(Page.of(request.getPage(), request.getSize()));

        return Pageable.<EmployeeEntity>builder()
                .content(query.list())
                .totalPages(query.pageCount())
                .hasPrevious(query.hasPreviousPage())
                .hasNext(query.hasNextPage())
                .build();
    }

这里的问题是为什么当

query.list()
被调用时 Hibernate 会产生两个 Select


Hibernate: 
    select
        ee1_0.id,
        ee1_0.employee_type_id,
        ee1_0.person_id,
        ee1_0.user_account_id 
    from
        core.employee ee1_0 
    order by
        ee1_0.id 
    offset
        ? rows 
    fetch
        first ? rows only

Hibernate: 
    select
        ete1_0.id,
        ete1_0.abbreviation,
        ete1_0.active,
        ete1_0.description,
        ete1_0.name 
    from
        type.employee_type ete1_0 
    where
        ete1_0.id = any (?)


当我有另一个实体(它是 EmployeeEntity 的父级)并在一个选择中获取所有类型表时,事情变得更加令人困惑

@Builder
@Getter @Setter
@NoArgsConstructor
@AllArgsConstructor
@Entity(name = "Person")
@Table(schema = "core", name = "person")
public class PersonEntity {

    @Id
    @SequenceGenerator(schema = "core", name = Sequence.PERSON_ID_SEQ, sequenceName = Sequence.PERSON_ID_SEQ)
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = Sequence.PERSON_ID_SEQ)
    @Column(name = "id", nullable = false, updatable = false)
    private Integer id;

    @Column(name = "first_name", length = 100, nullable = false)
    private String firstName;

    @Column(name = "last_name", length = 100, nullable = false)
    private String lastName;

    @Column(name = "document_number", length = 50, nullable = false)
    private String documentNumber;

    @Column(name = "document_type_id", nullable = false)
    private Integer documentTypeId;

    @Column(name = "gender_type_id", nullable = false)
    private Integer genderTypeId;

    @Column(name = "birth_date", nullable = false)
    private LocalDate birthDate;

    @Column(name = "email", nullable = false)
    private String email;

    @Column(name = "mobile_number", nullable = false)
    private String mobileNumber;

    @UpdateTimestamp
    @Column(name = "update_date", nullable = false)
    private LocalDateTime updateDate;

    @CreationTimestamp
    @Column(name = "create_date", nullable = false)
    private LocalDateTime createDate;

    @Builder.Default
    @Enumerated(EnumType.STRING)
    @Column(name = "active", length = 1, nullable = false)
    private Active active = Active.Y;

    @ManyToOne(fetch = FetchType.EAGER)
    @JoinColumn(name = "document_type_id", insertable = false, updatable = false)
    private DocumentTypeEntity documentType;

    @ManyToOne(fetch = FetchType.EAGER)
    @JoinColumn(name = "gender_type_id", insertable = false, updatable = false)
    private GenderTypeEntity genderType;

}
Hibernate: 
    select
        pe1_0.id,
        pe1_0.active,
        pe1_0.birth_date,
        pe1_0.create_date,
        pe1_0.document_number,
        dt1_0.id,
        dt1_0.abbreviation,
        dt1_0.active,
        dt1_0.description,
        dt1_0.name,
        pe1_0.document_type_id,
        pe1_0.email,
        pe1_0.first_name,
        gt1_0.id,
        gt1_0.abbreviation,
        gt1_0.active,
        gt1_0.description,
        gt1_0.name,
        pe1_0.gender_type_id,
        pe1_0.last_name,
        pe1_0.mobile_number,
        pe1_0.update_date 
    from
        core.person pe1_0 
    left join
        type.document_type dt1_0 
            on dt1_0.id=pe1_0.document_type_id 
    left join
        type.gender_type gt1_0 
            on gt1_0.id=pe1_0.gender_type_id 
    where
        pe1_0.id = any (?)

有人可以向我解释为什么 EmployeeEntity 会出现这种奇怪的行为,而 PersonEntity 却不会出现这种奇怪的行为

java hibernate jpa quarkus quarkus-panache
1个回答
0
投票

这实际上是正常的,因为在获取多个实体的请求中 fetchMode 被忽略。

我在新文档中找不到对此的引用,但是这个旧文档指出:

映射文档中定义的获取策略影响:

  • 通过 get() 或 load() 检索
  • 导航关联时隐式发生的检索
  • 条件查询
  • 如果使用子选择获取,则进行 HQL 查询

此更多最新文档

也提到了该行为

要解决您的问题,您可以使用 join fetch 或实体图(with spring data jpawithout

© www.soinside.com 2019 - 2024. All rights reserved.