代理如何加载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加载,代理如何知道属性的值?

你打电话时

 person.getType().getDescription() 

如果person正在引用尚未初始化的Hibernate代理,那么,是的,它将发出一个SQL查询来检索目标实体的字段值。

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

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

这不完全是Hibernate创建代理的方式,但它是一个很好的读取: 代理模式 。

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