Java JPA&;Hibernate:执行后续查询以获取所有数据,而不是只在一个查询中执行

Java JPA&;Hibernate:执行后续查询以获取所有数据,而不是只在一个查询中执行,java,hibernate,jpa,eager-loading,Java,Hibernate,Jpa,Eager Loading,我有以下疑问。我想知道为什么在使用JPA和Hibernate时,在manytone或OneToMany关系中执行急切加载时,它调用DB以获取实体信息,但另外,还会生成后续查询以获取每个子级 另一方面,当使用带有JOIN-FETCH的查询时,它会像我期望的那样执行查询,一次获取所有信息,因为fetchType表示为“EAGER” 这里是一个简单的例子: 我有一个班上的学生,他和班上的教室有着千丝万缕的联系 @Entity @Table(name = "STUDENT") public class

我有以下疑问。我想知道为什么在使用JPA和Hibernate时,在manytoneOneToMany关系中执行急切加载时,它调用DB以获取实体信息,但另外,还会生成后续查询以获取每个子级

另一方面,当使用带有JOIN-FETCH的查询时,它会像我期望的那样执行查询,一次获取所有信息,因为fetchType表示为“EAGER”

这里是一个简单的例子:

我有一个班上的学生,他和班上的教室有着千丝万缕的联系

@Entity
@Table(name = "STUDENT")
public class Student {

@ManyToOne(optional = true, fetch = FetchType.EAGER)
        @JoinColumn(name = "ClassroomID")
        private Classroom mainClass;
另一边是名为教室的班级,如下所示:

@Entity
public class Classroom {

@OneToMany(cascade = CascadeType.ALL, mappedBy = "mainClass", fetch = FetchType.EAGER)
private List<Student> studentsList;
然后它执行下一个查询的次数与分配给每个教室的学生的次数相同

  Hibernate: 
      /* load one-to-many com.hw.access.Classroom.classStudents */ 
      select
          classstude0_.ClassroomID as Classroo4_0_1_,
          classstude0_.id as id1_1_1_,
          classstude0_.id as id1_1_0_,
          classstude0_.FIRST_NAME as FIRST_NA2_1_0_,
          classstude0_.LAST_NAME as LAST_NAM3_1_0_,
          classstude0_.ClassroomID as Classroo4_1_0_ 
      from
          STUDENT classstude0_ 
      where
          classstude0_.ClassroomID=?
问题是:为什么不一次获取所有信息?为什么它不在一个查询中获取信息?因为它已经在那里执行Join子句了

为什么只在查询中显式添加Fetch时,它会执行请求的操作

例如:

SELECT
         r 
     FROM
         Classroom r 
     LEFT JOIN FETCH
         r.classStudents */ 
然后,输出查询只在一个查询中获取所有信息:

Hibernate: 

        select
              classroom0_.id as id1_0_0_,
              classstude1_.id as id1_1_1_,
              classroom0_.number as number2_0_0_,
              classstude1_.FIRST_NAME as FIRST_NA2_1_1_,
              classstude1_.LAST_NAME as LAST_NAM3_1_1_,
              classstude1_.ClassroomID as Classroo4_1_1_,
              classstude1_.ClassroomID as Classroo4_0_0__,
              classstude1_.id as id1_1_0__ 
          from
              Classroom classroom0_ 
          left outer join
              STUDENT classstude1_ 
                  on classroom0_.id=classstude1_.ClassroomID

默认情况下,fetchtype是lazy,这意味着如果您不在请求中请求列表,Hibernate将不会收集它

在第一个请求中,您请求教室r的所有属性,包括学生列表,以便Hibernate将惰性地加载它们(在发现您需要它们之后)


但是,当fetchtype设置为“急切休眠”时,即使您不请求,也可以将其收集。

由于您有一个从
课堂
学生
OneToMany
关系,使用单个查询将导致每行重复
课堂
字段。 现在假设你有第二个
OneToMany
关系,从
教室
到,比如说
课程
;如果对于给定的
教室
您有N个
学生
s和M个
课程
s,您将有一个查询返回N+M行,每个行都包含我在 在“急切获取不一致”下:

JPQL和Criteria查询都默认为select fetching,因此为每个单独的关联发出二次select。关联的数量越大,额外的个人选择越多,对应用程序性能的影响就越大

另外,请注意,Hibernate为HQL查询类似地忽略了获取注释:

Hibernate忽略我的外部join=“true”或fetch=“join”设置,并使用n+1选项惰性地获取关联

HQL查询始终忽略映射元数据中定义的外部联接或fetch=“join”的设置。此设置仅适用于使用get()或load()获取的关联、条件查询和图形导航。如果需要为HQL查询启用即时抓取,请使用显式左连接抓取

Hibernate: 

        select
              classroom0_.id as id1_0_0_,
              classstude1_.id as id1_1_1_,
              classroom0_.number as number2_0_0_,
              classstude1_.FIRST_NAME as FIRST_NA2_1_1_,
              classstude1_.LAST_NAME as LAST_NAM3_1_1_,
              classstude1_.ClassroomID as Classroo4_1_1_,
              classstude1_.ClassroomID as Classroo4_0_0__,
              classstude1_.id as id1_1_0__ 
          from
              Classroom classroom0_ 
          left outer join
              STUDENT classstude1_ 
                  on classroom0_.id=classstude1_.ClassroomID