Hibernate产生额外的sql

Hibernate产生额外的sql,hibernate,join,fetch,one-to-one,Hibernate,Join,Fetch,One To One,我有两个实体:父实体和子实体。他们之间有着“一对一”的关系 我有以下查询:从父p左join fetch p.child 如果父项中有一行不存在子项-1,例如hibernate,则会针对每种情况发出额外的查询 Hibernate: select parent0_.PARENT_ID as PARENT1_2_0_, child1_.CHILD_ID as CHILD1_3_1_, parent0_.CHILD_ID as CHILD2_2_

我有两个实体:父实体和子实体。他们之间有着“一对一”的关系

我有以下查询:从父p左join fetch p.child

如果父项中有一行不存在子项-1,例如hibernate,则会针对每种情况发出额外的查询

Hibernate: 
    select
        parent0_.PARENT_ID as PARENT1_2_0_,
        child1_.CHILD_ID as CHILD1_3_1_,
        parent0_.CHILD_ID as CHILD2_2_0_,
        child1_.NAME as NAME3_1_ 
    from
        PARENT parent0_ 
    left outer join
        CHILD child1_ 
            on parent0_.CHILD_ID=child1_.CHILD_ID
Hibernate: 
    select
        child0_.CHILD_ID as CHILD1_3_0_,
        child0_.NAME as NAME3_0_ 
    from
        CHILD child0_ 
    where
        child0_.CHILD_ID=?
代码如下:

@Entity
@Table(name = "PARENT")
public class Parent {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "PARENT_ID", nullable = false)
    private int id;

    @OneToOne(optional = true)
    @JoinColumn(name = "CHILD_ID")
    @NotFound(action = NotFoundAction.IGNORE)
    private Child child;
}

@Entity
@Table(name="CHILD")
public class Child {


    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "CHILD_ID", nullable = false)
    private int id;

    @Column(name = "NAME")
    private String name;
}
为什么会发生这种情况?如何防止这种额外的sql

以下是生成数据库的代码:

create table PARENT(
PARENT_ID INTEGER GENERATED ALWAYS AS IDENTITY,
CHILD_ID  INTEGER, 
PRIMARY KEY (PARENT_ID)
);

create table CHILD(
CHILD_ID  INTEGER GENERATED ALWAYS AS IDENTITY,
NAME VARCHAR(100) NOT NULL,
PRIMARY KEY (CHILD_ID)
);

insert into PARENT(CHILD_ID) values(-1);

正确设计数据库,不要在PARENT.child_ID列中存储不存在的子ID。如果父项没有子项,则在此列中存储NULL,并为该列创建外键约束,以确保该列始终保持NULL或有效的子ID


这将允许您从映射中删除@NotFound注释,并删除附加查询。事实上,当Hibernate执行第一个查询时,它会得到-1作为子ID。但是由于无法知道-1是否是有效的子ID,因此它必须执行额外的查询来确定子ID是否存在,因此应该在父ID中初始化,或者没有,因此应该在父级中设置为null。

您可能会尝试其他fetchtype

@OneToOne(optional = true, fetch = FetchType.EAGER)
private Child child;
但是,正如JB Nizet已经解释的那样,潜在的问题是存储在CHILD_ID字段中的虚构标识符


另一种策略是扭转这种关系,在父类的@OneToOne注释中添加mappedBy属性,并在子类中添加对父类的引用,或者只在子类中设置父类。

关于数据库设计,您完全正确。但我们有一些遗留数据库,我们必须以某种方式处理它。有什么解决办法吗?告诉Hibernate,如果结果sql中有null,不要尝试检查子项是否存在。如果有null,则不会检查。问题是不存在null,存在-1。好了,除了清理数据之外,没有其他解决办法。如果设置not found=ignore并急切地获取关联,Hibernate就无法解决这个问题,这让我感到困惑。如果您急切地获取关联,比如说,使用联接,那么Hibernate在理论上将能够发现ID与联接表中的任何行都不对应……因此它可以将其设置为null。@sbratla:可以,但我想他们没有实现此优化,因为NotFound从未在设计良好的模式中使用过。没错,但我还是要说Hibernate应该能够适应不同的设计,而不是相反。无论如何,这可能会成为一个长期的讨论…所以我想我们必须接受它是怎样的,并通过设计Hibernate:-D来处理它