简体   繁体   English

休眠条件 OneToOne FetchType.Eager FetchMode.Join 执行不必要的查询

[英]Hibernate criteria OneToOne FetchType.Eager FetchMode.Join execute unnecessary queryes

I have sample entity TableA and TableB, in table A we have column TABLE_B_ID annotated as bellow:我有示例实体 TableA 和 TableB,在表 A 中,我们有列 TABLE_B_ID 注释如下:

@OneToOne(fetch = FetchType.EAGER, optional = false)
@JoinColumn(name = "TABLE_B_ID")
@Fetch(FetchMode.JOIN)

Then when i execute simple code like this:然后当我执行这样的简单代码时:

Criteria c = session.createCriteria(TableA.class);
c.list();

Hibernate run query for n+1 times where n=number-of-row in TableA, even when TableA already joinned with TableB on the first query, Hibernate still trying to get TableB for each A by another select query. Hibernate 运行查询 n+1 次,其中表 A 中的 n=行数,即使在第一次查询时 TableA 已经与 TableB 连接,Hibernate 仍然试图通过另一个选择查询为每个 A 获取 TableB。

Query fired:查询已触发:

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=?

and so on..等等..

I already try to remove the FetchMode or change optional=true but the query fired is still n+1 times.我已经尝试删除FetchMode或更改optional=true但触发的查询仍然是 n+1 次。 What is the cause of hibernate firing another select even after he got the data on the first select query already?即使在他已经获得第一个选择查询的数据后,休眠触发另一个选择的原因是什么?

You are experiencing a well known problem, the "N+1 selects" problem occurs when you select a parent entity and hibernate will make additional select for a child related to the parent with OneToOne.您遇到了一个众所周知的问题,当您选择父实体时会出现“N+1 选择”问题,并且休眠将使用 OneToOne 为与父实体相关的子实体进行额外的选择。 So if you have "N" parent-child records in the database, hibernate will get all parents with one select and then get each child in separated select, making total N+1 selects.因此,如果您在数据库中有“N”条父子记录,hibernate 将获得所有父级的一个选择,然后将每个子级置于单独的选择中,总共 N+1 个选择。 There are two approaches for "N+1" problem in hibernate: 1. "Join Fetch" all OneToOne children. Hibernate 中的“N+1”问题有两种解决方法: 1. “Join Fetch”所有 OneToOne 孩子。 2. Enable the second level cache and use @Cache annotation on the OneToOne children. 2.启用二级缓存,并在OneToOne子节点上使用@Cache注解。

Your problem is that you didn't "join fetch" all of the OneToOne children.您的问题是您没有“加入获取”所有 OneToOne 孩子。 You must "join fetch" them all, including the transitive children (entities referenced from children themselves, or within the collection).您必须“加入获取”所有这些,包括可传递的子项(从子项本身或集合中引用的实体)。

Making OneToOne lazy (because its eager by default) is only partial solution, because hibernate will make a select for a child only when you access some getter on the child, but in long term it will still make all the N selects.使 OneToOne 懒惰(因为默认情况下它是渴望的)只是部分解决方案,因为只有当您访问孩子的某些 getter 时,hibernate 才会为孩子进行选择,但从长远来看,它仍然会进行所有 N 次选择。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM