【问题标题】:Controlling lazy/eager loading of @Formula columns dynamically动态控制 @Formula 列的延迟/急切加载
【发布时间】:2016-08-04 08:01:20
【问题描述】:

我们有一些实体,它们有一堆用 Hibernate 的 @Formula 注释注释的属性。注解中的 SQL sn-ps 主要运行标量子查询(例如COUNT 查询)。例如,我们有一个深度为四级的一对多关系层次结构:A <- B <- C <- D(其中<- 表示一对多关联)。通常在获取A 类型的实体时,我们想知道D 类型的关联实体的数量。为此,我们在A 中使用@Formula-annotated 属性。

由于我们并非每次都需要这些值,因此我们将 @Formula 属性声明为延迟加载(我们启用了 Hibernate 的字节码增强功能以​​实现这一点)。但是对于某些查询,我们希望急切地加载这些属性。我们经常在一个查询中加载数百个A 类型的实体,动态控制这些属性的急切/延迟加载在性能方面很重要。我们已经使用 JPA 的实体图来控制为某些查询急切加载哪些属性,但实体图似乎在这里不起作用。即使我们在实体图中列出了@Formula 属性,它们仍然是延迟加载的。

是否可以在每个查询的基础上动态控制 @Formula 列的延迟/急切加载?我们目前仅限于 JPA Criteria Query API,并且无法使用命名查询在这里。

更新:

所讨论的属性不是与其他实体的关联,而只是一些计算值。这意味着例如fetch profile 在这里不适用,因为它们只适用于实体关联(或者至少我是这样理解Hibernate manual)。以下是我们的 @Formula 属性之一的示例:

@Entity
public class A {

    @Basic(fetch = FetchType.LAZY)
    @Formula("(select count(*) from entity_D_table where ...)")
    private int associatedDCount;

    ...
}

【问题讨论】:

    标签: java hibernate jpa


    【解决方案1】:

    您可以使用 Critria api 使其返回 DTO 而不是实体。

    在您的条件查询中,使用 Projection 仅选择您需要的列。

    ProjectionList properties = Projections.projectionList();
    properties.add(Projections.property("id").as("id"));
    properties.add(Projections.property("name").as("name"));
    properties.add(Projections.property("lazyField").as("lazyField"));
    criteria.setProjection(properties);
    criteria.setResultTransformer(new AliasToBeanResultTransformer(MyEntityDTO.class));
    

    这样,选择查询将只包含您询问的字段,无论映射 EAGER 还是 LAZY。

    【讨论】:

    • 我们不使用 Hibernate 的 Criteria API,但我想这也可以通过 JPA Criteria Query API 实现。这将需要对我们当前的代码库进行大量更改,但如果当前的实现被认为很慢,这可能是值得的。并不能真正解决眼前的问题,但无论如何都要为这个想法+1。
    • 根据我的经验,当我只需要显示数据时,使用 DTO 而不是实体的性能要好得多:您可以控制连接数或列数,并且可以创建特定索引以加快速度查询更多
    • 嗯,连接的数量可以通过 JPA 实体图来控制,我的理解是获取太多列不应该对性能造成太大影响。但是,是的,使用您描述的 DTO 确实可以进行更多控制和微调。不过,至少在我们的情况下,它还需要更多的实现工作并增加代码复杂性,我不知道这是否是一个很好的权衡。
    【解决方案2】:

    您可以尝试查看 Hibernate 的 fetch profile https://docs.jboss.org/hibernate/orm/4.2/manual/en-US/html/ch20.html#performance-fetching-profiles

    例如,您可以像这样注释实体

    @Entity
    @FetchProfile(name = "country_states", fetchOverrides = {
               @FetchProfile.FetchOverride(entity = Country.class, association = "states", mode = FetchMode.JOIN)
    })
    public class Country implements Serializable {...
    

    并在查询时激活JOIN模式,如下所示:

     session=getSession();
     session.beginTransaction();
     //enable fetch profile for EAGER fetching
     session.enableFetchProfile("country_states");
    

    http://www.concretepage.com/hibernate/fetchprofile_hibernate_annotation所示

    【讨论】:

    • 但是获取配置文件不是仅适用于实体关联吗?我添加了一个代码示例,说明我们的属性是什么样的,我认为 fetch 配置文件在这里不起作用。
    • 你是对的。您是否可以考虑在数据库中定义一个 SQL 视图并在其上映射一个新实体,以便将公式作为一个简单属性急切地获取?
    • 我一直在考虑创建一个视图,但这需要对代码库进行大量更改。目前我们使用 JPA 实体图一次性从大约十几个表中急切地加载数据,并且代码期望它获取整个实体图。但如果目前的方法最终在基准测试方面过于缓慢,我们将不得不重新考虑这一点。
    猜你喜欢
    • 1970-01-01
    • 2015-09-30
    • 2011-08-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-03-14
    • 2017-06-03
    • 1970-01-01
    相关资源
    最近更新 更多