【问题标题】:Criteria Query fetches all the related entities if the where clause is not specified如果未指定 where 子句,则 Criteria Query 获取所有相关实体
【发布时间】:2019-01-30 10:18:27
【问题描述】:

我正在尝试运行一个简单的条件查询。但是,输出显示正在执行 4 个查询而不是单个查询,这是非常出乎意料的。

我想知道,我是否错过了域模型或标准查询中的任何约束。

下面是领域模型。

学生

    @Entity
    public class Student {

      @Id
      @GeneratedValue
      private Long id;

      @Column(nullable = false)
      private String name;

      @OneToOne(mappedBy="student", fetch = FetchType.LAZY)
      private Passport passport;

    ...
    }

护照

@Entity
public class Passport {

    @Id
    @GeneratedValue
    private Long id;

    @Column
    private String number;

    @OneToOne
    private Student student;

}

我已使用以下条件查询来获取学生记录。 关于关系映射,我还想提几点。

  • @ManyToMany@OneToMany 的关系默认为 LazyLoad。
  • 我已将@OneToOne 明确设置为Lazy 加载。

    CriteriaBuilder builder = em.getCriteriaBuilder();
    CriteriaQuery<Student> cq = builder.createQuery(Student.class);
    Root<Student> root = cq.from(Student.class);
    cq.select(root);
    //cq.where(builder.equal(root.get("id"), 10001L));
    List<Student> resultList = em.createQuery(cq).getResultList();
    resultList.forEach(s -> log.info("{}",s));
    

以下是输出:

    2019-01-30 15:34:40.883  INFO 13760 --- [           main] o.h.h.i.QueryTranslatorFactoryInitiator  : HHH000397: Using ASTQueryTranslatorFactory
    Hibernate: 
        select
            student0_.id as id1_4_,
            student0_.name as name2_4_ 
        from
            student student0_
    2019-01-30 15:34:41.436 TRACE 13760 --- [           main] o.h.type.descriptor.sql.BasicExtractor   : extracted value ([id1_4_] : [BIGINT]) - [2001]
    2019-01-30 15:34:41.444 TRACE 13760 --- [           main] o.h.type.descriptor.sql.BasicExtractor   : extracted value ([name2_4_] : [VARCHAR]) - [Irshad]
    2019-01-30 15:34:41.445 TRACE 13760 --- [           main] o.h.type.descriptor.sql.BasicExtractor   : extracted value ([id1_4_] : [BIGINT]) - [2002]
    2019-01-30 15:34:41.446 TRACE 13760 --- [           main] o.h.type.descriptor.sql.BasicExtractor   : extracted value ([name2_4_] : [VARCHAR]) - [Ahmad]
    2019-01-30 15:34:41.446 TRACE 13760 --- [           main] o.h.type.descriptor.sql.BasicExtractor   : extracted value ([id1_4_] : [BIGINT]) - [2003]
    2019-01-30 15:34:41.446 TRACE 13760 --- [           main] o.h.type.descriptor.sql.BasicExtractor   : extracted value ([name2_4_] : [VARCHAR]) - [Sheikh]
    2019-01-30 15:34:41.460 TRACE 13760 --- [           main] org.hibernate.type.CollectionType        : Created collection wrapper: [com.initgrep.jpademo.student.Student.addresses#2001]
    2019-01-30 15:34:41.460 TRACE 13760 --- [           main] org.hibernate.type.CollectionType        : Created collection wrapper: [com.initgrep.jpademo.student.Student.courses#2001]
    Hibernate: 
        select
            passport0_.id as id1_2_1_,
            passport0_.number as number2_2_1_,
            passport0_.student_id as student_3_2_1_,
            student1_.id as id1_4_0_,
            student1_.name as name2_4_0_ 
        from
            passport passport0_ 
        left outer join
            student student1_ 
                on passport0_.student_id=student1_.id 
        where
            passport0_.student_id=?
    2019-01-30 15:34:41.465 TRACE 13760 --- [           main] o.h.type.descriptor.sql.BasicBinder      : binding parameter [1] as [BIGINT] - [2001]
    2019-01-30 15:34:41.466 TRACE 13760 --- [           main] o.h.type.descriptor.sql.BasicExtractor   : extracted value ([id1_4_0_] : [BIGINT]) - [2001]
    2019-01-30 15:34:41.466 TRACE 13760 --- [           main] o.h.type.descriptor.sql.BasicExtractor   : extracted value ([id1_2_1_] : [BIGINT]) - [4001]
    2019-01-30 15:34:41.467 TRACE 13760 --- [           main] o.h.type.descriptor.sql.BasicExtractor   : extracted value ([number2_2_1_] : [VARCHAR]) - [E1001]
    2019-01-30 15:34:41.467 TRACE 13760 --- [           main] o.h.type.descriptor.sql.BasicExtractor   : extracted value ([student_3_2_1_] : [BIGINT]) - [2001]
    2019-01-30 15:34:41.475 TRACE 13760 --- [           main] org.hibernate.type.CollectionType        : Created collection wrapper: [com.initgrep.jpademo.student.Student.addresses#2002]
    2019-01-30 15:34:41.476 TRACE 13760 --- [           main] org.hibernate.type.CollectionType        : Created collection wrapper: [com.initgrep.jpademo.student.Student.courses#2002]
    Hibernate: 
        select
            passport0_.id as id1_2_1_,
            passport0_.number as number2_2_1_,
            passport0_.student_id as student_3_2_1_,
            student1_.id as id1_4_0_,
            student1_.name as name2_4_0_ 
        from
            passport passport0_ 
        left outer join
            student student1_ 
                on passport0_.student_id=student1_.id 
        where
            passport0_.student_id=?
    2019-01-30 15:34:41.476 TRACE 13760 --- [           main] o.h.type.descriptor.sql.BasicBinder      : binding parameter [1] as [BIGINT] - [2002]
    2019-01-30 15:34:41.477 TRACE 13760 --- [           main] o.h.type.descriptor.sql.BasicExtractor   : extracted value ([id1_4_0_] : [BIGINT]) - [2002]
    2019-01-30 15:34:41.477 TRACE 13760 --- [           main] o.h.type.descriptor.sql.BasicExtractor   : extracted value ([id1_2_1_] : [BIGINT]) - [4002]
    2019-01-30 15:34:41.477 TRACE 13760 --- [           main] o.h.type.descriptor.sql.BasicExtractor   : extracted value ([number2_2_1_] : [VARCHAR]) - [E1002]
    2019-01-30 15:34:41.478 TRACE 13760 --- [           main] o.h.type.descriptor.sql.BasicExtractor   : extracted value ([student_3_2_1_] : [BIGINT]) - [2002]
    2019-01-30 15:34:41.478 TRACE 13760 --- [           main] org.hibernate.type.CollectionType        : Created collection wrapper: [com.initgrep.jpademo.student.Student.addresses#2003]
    2019-01-30 15:34:41.478 TRACE 13760 --- [           main] org.hibernate.type.CollectionType        : Created collection wrapper: [com.initgrep.jpademo.student.Student.courses#2003]
    Hibernate: 
        select
            passport0_.id as id1_2_1_,
            passport0_.number as number2_2_1_,
            passport0_.student_id as student_3_2_1_,
            student1_.id as id1_4_0_,
            student1_.name as name2_4_0_ 
        from
            passport passport0_ 
        left outer join
            student student1_ 
                on passport0_.student_id=student1_.id 
        where
            passport0_.student_id=?
    2019-01-30 15:34:41.479 TRACE 13760 --- [           main] o.h.type.descriptor.sql.BasicBinder      : binding parameter [1] as [BIGINT] - [2003]
    2019-01-30 15:34:41.479 TRACE 13760 --- [           main] o.h.type.descriptor.sql.BasicExtractor   : extracted value ([id1_4_0_] : [BIGINT]) - [2003]
    2019-01-30 15:34:41.479 TRACE 13760 --- [           main] o.h.type.descriptor.sql.BasicExtractor   : extracted value ([id1_2_1_] : [BIGINT]) - [4003]
    2019-01-30 15:34:41.480 TRACE 13760 --- [           main] o.h.type.descriptor.sql.BasicExtractor   : extracted value ([number2_2_1_] : [VARCHAR]) - [E1003]
    2019-01-30 15:34:41.480 TRACE 13760 --- [           main] o.h.type.descriptor.sql.BasicExtractor   : extracted value ([student_3_2_1_] : [BIGINT]) - [2003]
    2019-01-30 15:34:41.480 DEBUG 13760 --- [           main] o.h.stat.internal.StatisticsImpl         : HHH000117: HQL: select generatedAlias0 from Student as generatedAlias0, time: 61ms, rows: 3
    2019-01-30 15:34:41.484  INFO 13760 --- [           main] i.StatisticalLoggingSessionEventListener : Session Metrics {
        170294 nanoseconds spent acquiring 1 JDBC connections;
        0 nanoseconds spent releasing 0 JDBC connections;
        **5107615 nanoseconds spent preparing 4 JDBC statements;
        5699493 nanoseconds spent executing 4 JDBC statements;**
        0 nanoseconds spent executing 0 JDBC batches;
        0 nanoseconds spent performing 0 L2C puts;
        0 nanoseconds spent performing 0 L2C hits;
        0 nanoseconds spent performing 0 L2C misses;
        0 nanoseconds spent executing 0 flushes (flushing a total of 0 entities and 0 collections);
        0 nanoseconds spent executing 0 partial-flushes (flushing a total of 0 entities and 0 collections)

我假设,条件查询不尊重实体上声明的FetchType.LAZY。因为Student -&gt; Passport1-1 关系。它被急切地获取。

如果我添加以下 where 子句。

cq.where(builder.equal(root.get("id"), 10001L))

它只获取学生,没有获取其他关系,如下面的输出所验证。

        Hibernate: 
        select
            student0_.id as id1_4_,
            student0_.name as name2_4_ 
        from
            student student0_ 
        where
            student0_.id=10001
    2019-01-30 15:43:12.662 DEBUG 5964 --- [           main] o.h.stat.internal.StatisticsImpl         : HHH000117: HQL: select generatedAlias0 from Student as generatedAlias0 where generatedAlias0.id=10001L, time: 22ms, rows: 0
    2019-01-30 15:43:12.665  INFO 5964 --- [           main] i.StatisticalLoggingSessionEventListener : Session Metrics {
        169108 nanoseconds spent acquiring 1 JDBC connections;
        0 nanoseconds spent releasing 0 JDBC connections;
        4718825 nanoseconds spent preparing 1 JDBC statements;
        7554940 nanoseconds spent executing 1 JDBC statements;
        0 nanoseconds spent executing 0 JDBC batches;
        0 nanoseconds spent performing 0 L2C puts;
        0 nanoseconds spent performing 0 L2C hits;
        0 nanoseconds spent performing 0 L2C misses;
        0 nanoseconds spent executing 0 flushes (flushing a total of 0 entities and 0 collections);
        0 nanoseconds spent executing 0 partial-flushes (flushing a total of 0 entities and 0 collections)

更新:插入脚本。

INSERT INTO STUDENT(id,name) VALUES (2001, 'Irshad');
INSERT INTO STUDENT(id,name) VALUES (2002, 'Ahmad');
INSERT INTO STUDENT(id,name) VALUES (2003, 'Sheikh');

INSERT INTO PASSPORT(id, number, student_id) VALUES (4001, 'E1001', 2001);
INSERT INTO PASSPORT(id, number, student_id) VALUES (4002, 'E1002', 2002);
INSERT INTO PASSPORT(id, number, student_id) VALUES (4003, 'E1003', 2003);

【问题讨论】:

  • 只是为了确定:导致延迟关系被加载的不是你的 Student.toString() 记录器调用的方法,对吧?
  • @RobbyCornelissen 如果是由于toString(),那么在使用where 子句时应该不会产生影响。此外,toString() 实现只显示学生的ID and NAME
  • JPA 规范说:“LAZY 策略是对持久性提供程序运行时的提示”(即 JPA 2.0,第 11.1.37 章)。您的 JPA 实现决定了最佳方法是什么。
  • 您似乎只有 3 个学生记录,ID 分别为 2001、2002 和 2003,因此当您查找 ID 为 10001 的学生时,它找不到任何记录,也没有必要加载 Passport。尝试在 where 子句中将 id 更改为 2003 以查看您获得了多少查询。
  • @RezaNasiri 我已经用插入脚本更新了这个问题。每个学生只有一本护照。我仍然按照您的建议使用不同的 ID 运行,但这没有任何区别。任何其他想法

标签: java jpa h2 criteria-api


【解决方案1】:

由于您在 Student 实体中使用 mappedby,它使 Passport 成为关系的所有者,并且必须在加载 Student 时加载它。 一种选择是让 Student 成为这样的所有者:

学生映射

 @OneToOne( fetch = FetchType.LAZY)
 private Passport passport;

护照映射

@OneToOne(mappedBy="passport")
private Student student;

通过这样做passport_id 将被添加到学生表中。如果您无法做到这一点,您可以将 OneToOne 关系设为单向(学生 -> 护照)或使用 NO_PROXY 选项。

【讨论】:

  • 同意并且有效。但是,如果我想获取所有护照,则会发生同样的情况,因为学生现在是关系的所有者。看起来我们只能在一个方向上查询,以避免获取相关实体并触发额外的查询。
  • 正确。看起来您只能在一对一关系的一侧进行延迟加载。
猜你喜欢
  • 2014-10-03
  • 2011-11-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-07-20
  • 1970-01-01
  • 1970-01-01
  • 2015-07-14
相关资源
最近更新 更多