![](/img/trans.png)
[英]JPA Hibernate FetchType.EAGER and FetchMode.JOIN for non primary key
[英]Hibernate criteria OneToOne FetchType.Eager FetchMode.Join execute unnecessary queryes
我有示例实体 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 次,其中表 A 中的 n=行数,即使在第一次查询时 TableA 已经与 TableB 连接,Hibernate 仍然试图通过另一个选择查询为每个 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 次。 即使在他已经获得第一个选择查询的数据后,休眠触发另一个选择的原因是什么?
您遇到了一个众所周知的问题,当您选择父实体时会出现“N+1 选择”问题,并且休眠将使用 OneToOne 为与父实体相关的子实体进行额外的选择。 因此,如果您在数据库中有“N”条父子记录,hibernate 将获得所有父级的一个选择,然后将每个子级置于单独的选择中,总共 N+1 个选择。 Hibernate 中的“N+1”问题有两种解决方法: 1. “Join Fetch”所有 OneToOne 孩子。 2.启用二级缓存,并在OneToOne子节点上使用@Cache注解。
您的问题是您没有“加入获取”所有 OneToOne 孩子。 您必须“加入获取”所有这些,包括可传递的子项(从子项本身或集合中引用的实体)。
使 OneToOne 懒惰(因为默认情况下它是渴望的)只是部分解决方案,因为只有当您访问孩子的某些 getter 时,hibernate 才会为孩子进行选择,但从长远来看,它仍然会进行所有 N 次选择。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.