一尘不染

Hibernate忽略fetchgraph

hibernate

这是我的实体:

public class PersonItem implements Serializable{
    @Id
    @Column(name="col1")
    private String guid;

    @Column(name="col2")
    private String name;

    @Column(name="col3")
    private String surname;

    @Column(name="col4")
    private Date birthDate;
 //+getters and setters
}

这是我获得人员名单的方式:

Query query = em.createQuery("Select p from PersonItem p WHERE p.guid IN (:guids)");
EntityGraph<PersonItem> eg = em.createEntityGraph(PersonItem.class);
eg.addAttributeNodes("guid");
eg.addAttributeNodes("name");
eg.addAttributeNodes("surname");
query.setHint("javax.persistence.fetchgraph", eg);
query.setParameter("guids", guids);
List<PersonItem> list=query.getResultList();
em.close();
// And now I iterate result AFTER EM CLOSE
....iterate

如果我正确理解提取图,则它必须仅加载我指定的那些字段。但是,字段“ birthDate”也已加载。此外,我看到在hibernateSQL查询中选择了4列。

如何解决?我使用hibernate 5.1.0作为JPA提供程序。


阅读 210

收藏
2020-06-20

共1个答案

一尘不染

实体图旨在控制延迟或渴望加载哪些关系(例如,一对一,一对多等)。它们可能不适用于加载各个列(取决于提供程序)。

Hibernate有一些这方面的支持,但它是相当难以得到工作,描述在这里。但是,他们提到对这种方法的以下态度(我全心全意地同意):

请注意,这主要是一种营销功能;优化行读取比优化列读取重要得多。

因此,在您确认这确实是应用程序的瓶颈之前,我不建议您走得太远(例如,这种获取调整可能是过早优化的征兆)。

更新:

如前所述,JPA确实将是否懒惰地获取简单列(非关联)留给了提供者。

EAGER策略是对持久性提供程序运行时的要求,必须热切地获取数据。LAZY策略向持久性提供程序运行时提供了提示,即首次访问数据时应延迟获取数据。该实现被允许急切地获取已为其指定LAZY策略提示的数据。特别是,懒惰获取可能仅适用于使用基于属性的访问的基本映射。

从Hibernate 5开始,增加了对字节码增强的官方支持,这可能允许懒惰的属性获取。

最新的Hibernate文档中,我们可以得到:

2.3.2

fetch-FetchType(默认为EAGER)

定义该属性是应立即获取还是应延迟获取。JPA说,EAGER是提供程序(hibernate)的一项要求,即在提取所有者时应提取值,而LAZY只是提示在访问属性时要提取值。除非您使用字节码增强功能,否则Hibernate对于基本类型将忽略此设置。

下一个片段描述了字节码增强的优点。

延迟属性加载

将其视为部分加载支持。从本质上讲,您可以告诉Hibernate在从数据库中获取时仅应加载实体的一部分,以及何时应加载其他部分。请注意,这与基于代理的延迟加载思想非常不同,后者以实体为中心,在这种情况下,根据需要立即加载实体的状态。通过字节码增强,可以根据需要加载单个属性或属性组。

2020-06-20