Java 休眠条件OneToOne FetchType.Eager FETCHTMODE.Join执行不必要的查询是
我有示例实体TableA和TableB,在表A中我们有列table_B_ID,注释如下:Java 休眠条件OneToOne FetchType.Eager FETCHTMODE.Join执行不必要的查询是,java,hibernate,hibernate-criteria,Java,Hibernate,Hibernate Criteria,我有示例实体TableA和TableB,在表A中我们有列table_B_ID,注释如下: @OneToOne(fetch = FetchType.EAGER, optional = false) @JoinColumn(name = "TABLE_B_ID") @Fetch(FetchMode.JOIN) 然后,当我执行如下简单代码时: Criteria c = session.createCriteria(TableA.class); c.list(); Hibernate运行查询n+1次
@OneToOne(fetch = FetchType.EAGER, optional = false)
@JoinColumn(name = "TABLE_B_ID")
@Fetch(FetchMode.JOIN)
然后,当我执行如下简单代码时:
Criteria c = session.createCriteria(TableA.class);
c.list();
Hibernate运行查询n+1次,其中n=TableA中的行数,即使在第一次查询时TableA已经与TableB连接,Hibernate仍然试图通过另一个select查询为每个A获取TableB
已激发查询:
Hibernate:
select
this_.id as id1_0_1_,
this_.name as name2_0_1_,
this_.TABLE_B_ID as TABLE_B_3_0_1_,
tableb2_.id as id1_1_0_,
tableb2_.name as name2_1_0_
from
TABLE_A this_
inner join
TABLE_B tableb2_
on this_.TABLE_B_ID=tableb2_.id
Hibernate:
select
tablea0_.id as id1_0_1_,
tablea0_.name as name2_0_1_,
tablea0_.TABLE_B_ID as TABLE_B_3_0_1_,
tableb1_.id as id1_1_0_,
tableb1_.name as name2_1_0_
from
TABLE_A tablea0_
inner join
TABLE_B tableb1_
on tablea0_.TABLE_B_ID=tableb1_.id
where
tablea0_.TABLE_B_ID=?
Hibernate:
select
tablea0_.id as id1_0_1_,
tablea0_.name as name2_0_1_,
tablea0_.TABLE_B_ID as TABLE_B_3_0_1_,
tableb1_.id as id1_1_0_,
tableb1_.name as name2_1_0_
from
TABLE_A tablea0_
inner join
TABLE_B tableb1_
on tablea0_.TABLE_B_ID=tableb1_.id
where
tablea0_.TABLE_B_ID=?
等等
我已经尝试删除FetchMode
或更改optional=true
,但仍然触发了n+1次查询。
即使hibernate已经获得了第一个select查询中的数据,他仍会触发另一个select的原因是什么?您遇到了一个众所周知的问题,当您选择一个父实体时,会出现“N+1 selects”问题,hibernate将对与OneToOne父实体相关的子实体进行额外选择。因此,如果数据库中有“N”个父子记录,hibernate将通过一次选择获取所有父项,然后在单独的选择中获取每个子项,使总选择数为N+1。 对于hibernate中的“N+1”问题,有两种方法: 1.“加入并取回”所有OneTONE儿童。 2.启用二级缓存并在OneTONE子级上使用@cache注释 你的问题是你没有“加入”所有的OneToOne孩子。您必须“连接”它们,包括可传递的子对象(从子对象本身或集合中引用的实体)
使OneToOne变为懒惰(因为默认情况下它是渴望的)只是部分解决方案,因为hibernate只有在您访问子对象上的某个getter时才会为该子对象进行选择,但从长远来看,它仍然会进行所有N次选择。您是否尝试过使用FetchType.LAZYI想要渴望的加载您是否尝试过内部/外部联接!可能是tableB比tableA多了一行。这只是一个示例表,所以没有您提到的复杂性,您可以看到第一个连接应该满足所有需要的信息,所以这与获取问题无关@缓存也不起作用。