当前位置: 首页 > 知识库问答 >
问题:

避免子集合元素关联的n1急切获取

安承教
2023-03-14

我有以下课程:

@Entity
@Table(name = "base")
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name = "DISCRIMINATOR", discriminatorType = DiscriminatorType.STRING)
@ForceDiscriminator
public class Base {
    // ...
}

@Entity
@DiscriminatorValue("foo")
public class Foo extends Base {
    @OneToMany( mappedBy = "foo", cascade=CascadeType.ALL )
    private List<Bar> bars = new ArrayList<Bar>();

    // ...
}

@Entity
public class Bar {
    @ManyToOne (optional = false)
    @JoinColumn(name = "foo_id" )
    private Foo foo;

    @OneToOne
    @JoinColumn(name = "baz_id", nullable = false)
    private Baz baz;

    //...
}

@Entity
public class Baz {
    // ...
}

现在我基本上想加载所有的Base,但在适用时渴望加载条,所以我使用以下查询:

SELECT b FROM Base b LEFT JOIN FETCH b.bars

虽然这是可行的,但它似乎为Bar实体生成了一个SELECT N 1问题:

Hibernate: /* SELECT b FROM Base b LEFT JOIN FETCH b.bars */ SELECT ...
Hibernate: /* load com.company.domain.Baz */ SELECT ...
Hibernate: /* load com.company.domain.Baz */ SELECT ...

有没有可能告诉hibernate急切地为子集合中的每个元素加载关联,而不使用N 1 SELECTs?

我尝试了以下查询的思路,这显然不起作用,因为它是一个集合:

SELECT b FROM Base b LEFT JOIN FETCH b.bars LEFT JOIN FETCH b.bars.baz
//Results in: illegal attempt to dereference collection [Foo.id.bars] with element property reference [baz]

我还尝试在(b.bar)bar中使用,虽然这允许我引用子集合,但它似乎并不急于加载作为我目标的bar集合。

解释为什么会发生这种情况也很好,因为我似乎无法理解。


共有3个答案

朱令
2023-03-14

我想说,在这种情况下,抓取策略的改变可能会有所帮助。文件说:

http://docs.jboss.org/hibernate/orm/4.1/manual/en-US/html_single/#performance-取数批

摘录:

您还可以启用集合的批获取。例如,如果每个人都有一个懒散的猫集合,并且会话中当前加载了10个人,那么遍历所有人将生成10个选择,每个对getCats()的调用一个选择。如果在Person映射中为cats集合启用批取,Hibernate可以预取集合:

<class name="Person">
    <set name="cats" batch-size="3">
        ...
    </set>
</class>

如果批处理大小为3,Hibernate将在四个SELECT中加载3、3、3、1个集合。同样,属性的值取决于特定会话中未初始化集合的预期数量。

我正在使用它,它工作得很好。如果我正在分页,并且总是只选择20条记录,批处理大小="20"工作得很好。如果我需要20个以上,仍然减少对DB的调用

田远
2023-03-14

我的方法(我的二级实体数量有限且稳定)

首先,让所有酒吧进入会话:

 SELECT bar FROM Bar bar

之后,所有条形图实体都将在缓存中,您的查询将能够访问它们,而无需其他实体。

濮丁雷
2023-03-14

如果您想检索未选择(n 1)的Bar和Baz,请使用以下hql。

SELECT b FROM Base b LEFT JOIN FETCH b.bars bar LEFT JOIN FETCH bar.baz

这应该只导致一个sql。

此外,如果您不想获取“Baz”,只需从酒吧创建关联即可-

默认情况下,JPA强制执行“渴望”获取“@OneToOne”和“@ManyToOne”关联。所以,你必须明确地让它变得懒惰,如下所示。

@Entity
public class Bar {

    @OneToOne
    @JoinColumn(name = "baz_id", nullable = false, fetch=FetchType.Lazy)
    private Baz baz;

    //...
}
 类似资料:
  • 问题内容: 我有以下课程: 现在,我基本上想加载all ,但在适用时渴望加载条,所以我使用以下查询: 在这种情况下,似乎为Bar实体产生了SELECT N + 1问题: 是否可以告诉hibernate急切地为子集合中的每个元素加载一个关联,而无需诉诸N + 1 SELECT? 我尝试了以下查询,但由于它是一个集合,因此显然无法正常工作: 我也尝试使用,虽然这使我可以引用子集合,但似乎并没有急于加载

  • 问题内容: 假设项目和出价是实体:一个项目有很多出价。它们在 Hibernate 中以典型的父/子关系映射: 在执行此查询后尝试访问每个项目的出价时,如何避免n + 1个选择? 请注意, 我需要 急切 的竞标价格,但 对收款 要有 进一步的限制 (b.amount> 100) 我尝试了以下失败: 问题答案: 这说明了为什么对fetch-joined集合添加限制会导致集合未初始化( 请注意 ,没有限

  • 我的Spring数据存储库被配置为默认@RepositoryRestResources,没有任何自定义。 JPA实体: ..... 我希望House obkect以JSON格式返回,作为Flat对象的嵌入部分,但只获取House的URL /仓库/公寓/442991: 同时,User-Role OneTo多项关系被取好,角色名为: 请求:/repository/users/5 除了关系类型,我不知道

  • 问题内容: 我有一个宽度为70%的元素,它漂浮在一个宽度为30%的元素旁边,但是当我添加填充时,它会扩展元素并破坏格式,有没有办法使它仅增加内容距离边缘而不是仅仅扩大它? 问题答案: 使用模型时,边框大小中将包含填充。

  • 我见过几个类似的问题有0个好答案。 这应该非常简单。我正在使用 Java JPA,有时想要加载子实体列表,但不是所有时间。不幸的是,当我说要懒惰地获取它时,JPA似乎没有听我的话。我已经 100% 确定在我的代码中没有任何地方以任何方式访问 childEntities 属性。但是,在我的 JPA.em(.)查找(.)调用时,所有子实体仍然会立即加载。这就是我如何声明与注释的关系。 我是这样加载父实