我有以下课程:
@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 SELECT?
我尝试了以下查询的内容,这显然不起作用,因为它是一个集合:
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]
我也尝试过使用IN(b.bars) bars
,虽然这允许我引用子集合,但它似乎并不急于加载我的目标吧集合。
解释为什么会发生这种情况也很好,因为我似乎无法弄明白。
答案 0 :(得分:5)
如果你想用out(n + 1)选择检索Bar和Baz,请使用以下hql。
SELECT b FROM Base b LEFT JOIN FETCH b.bars bar LEFT JOIN FETCH bar.baz
这应该只产生一个sql。
另外,如果您不想获取'Baz',只需从Bar-&gt; Baz'懒惰'进行关联。
JPA默认强制'eager'获取'@OneToOne'和'@ManyToOne'关联。所以,你必须明确地使它变得懒惰,如下所示。
@Entity
public class Bar {
@OneToOne
@JoinColumn(name = "baz_id", nullable = false, fetch=FetchType.Lazy)
private Baz baz;
//...
}
答案 1 :(得分:0)
我的方法(我有一个有限的,稳定数量的二级实体)
首先,让所有酒吧进入会话:
SELECT bar FROM Bar bar
之后,所有Bar实体都将位于缓存中,您的查询将无需其他实体即可访问它们。
答案 2 :(得分:0)
我想说在这种情况下,获取策略的改变可能会有所帮助。文档说:
http://docs.jboss.org/hibernate/orm/4.1/manual/en-US/html_single/#performance-fetching-batch
提取:
您还可以启用批量提取集合。例如,如果 每个人都有一个懒惰的猫集合,10人 目前在Session中加载,遍历所有人都会 生成10个SELECT,每次调用getCats()一个。如果启用 在Person的映射中批量获取cats集合, Hibernate可以预取集合:
<class name="Person">
<set name="cats" batch-size="3">
...
</set>
</class>
批量大小为3时,Hibernate将加载3个,3个,3个,1个集合 四个SELECT。同样,属性的值取决于 预期的特定会话中未初始化的集合数。
我正在使用它并且效果很好。如果我正在分页并且总是只选择20条记录,则批量大小=“20”的效果很好。如果我需要20以上,那么对DB的调用仍会减少