当要求加载惰性字段时,Hibernate 加载所有惰性字段

adr*_*mir 6 hibernate lazy-loading

我在Student和之间有一个 one2one 关系Address。我希望firstNamelastName字段Student被延迟加载。我也想懒惰的address领域。

这些是我的实体类:

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

  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  private Long id;

  @OneToOne(mappedBy = "student", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
  @LazyToOne(LazyToOneOption.NO_PROXY)
  private Address address;

  @Basic(fetch = FetchType.LAZY)
  @Column(name = "first_name")
  private String firstName;

  @Basic(fetch = FetchType.LAZY)
  @Column(name = "last_name")
  private String lastName;

  // getters and setters
}
Run Code Online (Sandbox Code Playgroud)

地址类:

@Entity
@Table(name = "addresses")
public class Address {

  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  private Long id;

  @OneToOne
  @JoinColumn(name = "s_id")
  private Student student;

  @Column
  private String street;

  // getters and setters
}
Run Code Online (Sandbox Code Playgroud)

我的测试方法如下所示(Java 8 lambda 只是在后面创建一个实体管理器并在事务中执行所有内容):

@Test
public void dummyTest() {
  JPA_UTILS.runInTransaction(e -> {
    Student s = e.find(Student.class, 150L);
    System.out.println("----------++++++++++++++-----------");
    s.getFirstName();
    System.out.println("----------++++++++++++++-----------");
  });
}
Run Code Online (Sandbox Code Playgroud)

所以在这里我从数据库加载一个现有的学生,然后获取惰性属性firstName(映射到first_name列)。问题是,Hibernate并不只加载firstNamelastNameaddress字段:

just.hibernate.one2one.TestApp > dummyTest STANDARD_OUT
  Hibernate: 
    select
      student0_.id as id1_1_0_ 
    from students student0_ 
    where student0_.id=?
  ----------++++++++++++++-----------
  Hibernate: 
     /* sequential select just.hibernate.one2one.Student */
    select
      student_.first_name as first_na2_1_,
      student_.last_name as last_nam3_1_ 
    from students student_ 
    where student_.id=?
  Hibernate: 
    /* load just.hibernate.one2one.Address */
    select
      address0_.id as id1_0_1_,
      address0_.street as street2_0_1_,
      address0_.s_id as s_id3_0_1_,
      student1_.id as id1_1_0_ 
    from addresses address0_ 
    left outer join students student1_  on address0_.s_id=student1_.id 
    where address0_.s_id=?
  ----------++++++++++++++-----------
Run Code Online (Sandbox Code Playgroud)

我不想要这种行为,我只想加载我请求的内容。有人可以帮我找到问题吗?

谢谢

更新1:

检测是用 maven 完成的,我只发布了相关的代码(我已经尝试过使用 gradle 并且结果相同)

just.hibernate.one2one.TestApp > dummyTest STANDARD_OUT
  Hibernate: 
    select
      student0_.id as id1_1_0_ 
    from students student0_ 
    where student0_.id=?
  ----------++++++++++++++-----------
  Hibernate: 
     /* sequential select just.hibernate.one2one.Student */
    select
      student_.first_name as first_na2_1_,
      student_.last_name as last_nam3_1_ 
    from students student_ 
    where student_.id=?
  Hibernate: 
    /* load just.hibernate.one2one.Address */
    select
      address0_.id as id1_0_1_,
      address0_.street as street2_0_1_,
      address0_.s_id as s_id3_0_1_,
      student1_.id as id1_1_0_ 
    from addresses address0_ 
    left outer join students student1_  on address0_.s_id=student1_.id 
    where address0_.s_id=?
  ----------++++++++++++++-----------
Run Code Online (Sandbox Code Playgroud)

Rad*_*ler 5

有两个基本资源可以正确理解这个问题。首先,属性的延迟加载不是标准设置。看:

Hibernate 支持延迟获取单个属性。这种优化技术也称为获取组。请注意,这主要是一项营销功能;优化行读取比优化列读取重要得多。但是,在极端情况下,仅加载类的某些属性可能很有用。

其次,基于上述 doc 部分,有一篇关于此的详细文章:

虽然这和NHibernate有关,但内容是一样的,因为这个特性来自Hibernate。

我们可以在那里阅读:

多个惰性属性呢?NHibernate 支持它们,但您需要记住一件事。NHibernate 将加载实体的所有惰性属性,而不仅仅是立即访问的属性。出于同样的原因,您不能急切地从 HQL 中加载实体的某些惰性属性。

再一次,我们可以理解lazy属性的设置不是标准设置。它适用于一些非常具体的情况,例如:

此功能主要用于特殊情况,例如Person.ImagePost.Text等。像往常一样,过度使用它时要小心。

总结:延迟加载属性(值类型/字符串,而不是关联)适用于特殊情况。它应该可以帮助我们避免加载一些巨大的列。但是,一旦访问了这样的属性,所有其他属性也会加载

  • 简单地说,你不能 :) 。感谢 Radim,让 Hibernate 团队蒙羞! (4认同)