代理如何加载Hibernate / JPA中的惰性属性

时间:2013-11-12 18:49:34

标签: java hibernate jpa

嗯,我的疑问非常简单:为了获得最佳性能,建议在我不需要使用的属性中使用始终延迟初始化(这很明显)。所以,想象下面的课程:

  @Entity
  public class Person{
    @Column
    private String name;
    @ManyToOne(fetch = FetchType.Lazy)
    @JoinColumn(name = "id_type")
    private TypePerson type;
 }

在我的主类中,我调用了没有初始化“type”属性的Person,如下面的那样:

 public void init(){
    //in this point "type" attribute is not initialized
    Person person = dao.find("Select * from Person where id = 12");

    //proxys work here to get description of "type" attribute
    System.out.println(person.getType().getDescription());
  }

因此,我从dataBase获取一个简单的Person对象,并在控制台上打印人的类型。在这一刻,代理CGLIB工作并做你的魔术,一切正常。

但是我在这里提出问题:

1 - 当我请求“getType()”时,Hibernate(或其他机制)在幕后进行SQL查询?例如:“SELECT * FROM TypePerson,其中id = 3”。

如果答案是肯定的:这种获取属性值的方法可能非常痛苦,因为我认为Hibernate每次都会在数据库中进行,以便在幕后获取这些信息。

如果答案为否:如果未从dataBase加载,代理如何知道属性的值?

2 个答案:

答案 0 :(得分:3)

致电时

person.getType().getDescription()

如果person引用尚未初始化的Hibernate代理,则是,它会发出SQL查询以检索目标实体的字段值。

  

获取属性值的这种方法可能非常痛苦,因为我   认为Hibernate每次都会在数据库中获取这些信息   在幕后。

每个代理只会执行一次。当它第一次出现时,它将在代理上设置一个标志,指示它已初始化,因此底层目标实体具有正确的值。如果加载了所有值,则不需要返回数据库。

这不是Hibernate创建代理的原因,但这是一个很好的阅读:Proxy Pattern

答案 1 :(得分:1)

  1. 实际上,当getDescription()返回的代理上调用person.getType()方法时,它会进入数据库。
  2. 仅当您在代理上调用方法时才会进入数据库,即当您确实要加载代理所包装的实体的状态时。它在会话生命周期中只执行一次。下一次调用代理方法将不再进入数据库,因为代理已经被前一个方法调用初始化了。 当然,它需要查询数据库。如何在不查询的情况下从数据库中获取数据?惰性代理的优点正是它只在需要时才检索状态。如果您事先知道您需要人员类型,则要么不使用惰性代理,要么使用在单个查询中加载此人及其类型的查询。这取决于你。