gpt4 book ai didi

如果定义了双向关系,Hibernate 会执行两次相同的查询

转载 作者:行者123 更新时间:2023-12-01 18:46:21 26 4
gpt4 key购买 nike

我正在使用 Hibernate 4.3.8.Final 和 Oracle 11g 数据库。我在两个实体之间定义了一个非常简单的双向关系,名为 Parent 和 Child,如下所示(省略了 getter 和 setter):

@Entity
public class Parent {

@Id
private Long id;

@OneToOne(mappedBy="parent",fetch=FetchType.LAZY)
private Child child;
}

@Entity
public class Child {

@Id
private Long id;

@OneToOne(fetch=FetchType.EAGER)
@JoinColumn(name="PARENT_ID")
private Parent parent;
}

生成对应表的SQL代码为:

CREATE TABLE PARENT
(
ID NUMBER(10)
);
CREATE UNIQUE INDEX PARENT_PK ON PARENT(ID);
ALTER TABLE PARENT ADD (
CONSTRAINT PARENT_PK
PRIMARY KEY
(ID)
USING INDEX PARENT_PK
ENABLE VALIDATE);

--------------

CREATE TABLE CHILD
(
ID NUMBER(10),
PARENT_ID NUMBER(10) NOT NULL
);

CREATE UNIQUE INDEX CHILD_PK ON CHILD (ID);

CREATE UNIQUE INDEX CHILD_U01 ON CHILD (PARENT_ID);

ALTER TABLE CHILD ADD (
CONSTRAINT CHILD_PK
PRIMARY KEY
(ID)
USING INDEX CHILD_PK
ENABLE VALIDATE,
CONSTRAINT CHILD_U01
UNIQUE (PARENT_ID)
USING INDEX CHILD_U01
ENABLE VALIDATE);

ALTER TABLE CHILD ADD (
CONSTRAINT CHILD_R01
FOREIGN KEY (PARENT_ID)
REFERENCES PARENT (ID)
ENABLE VALIDATE);

结构非常简单:子级通过外键(PARENT_ID)链接到父级,该外键也是唯一的。使用以下代码从数据库检索子实例:

entityManager.find(Child.class,1l);

Hibernate 执行两个查询。似乎第一个用于加载关系的第一个方向(从子到父),第二个用于加载另一个关系(从父到子):

SELECT child0_.id AS id1_0_0_,
child0_.PARENT_ID AS PARENT_ID2_0_0_,
parent1_.id AS id1_1_1_
FROM Child child0_
LEFT OUTER JOIN
Parent parent1_
ON child0_.PARENT_ID = parent1_.id
WHERE child0_.id = ?;

SELECT child0_.id AS id1_0_1_,
child0_.PARENT_ID AS PARENT_ID2_0_1_,
parent1_.id AS id1_1_0_
FROM Child child0_
LEFT OUTER JOIN
Parent parent1_
ON child0_.PARENT_ID = parent1_.id
WHERE child0_.PARENT_ID = ?;

子项配置为立即加载父项,因此第一个查询是正确的:子项表和父项表已连接并获取。我尝试将Parent的“child”属性的获取策略设置为LAZY,以防止第二次查询,但没有效果。

如何使用单个查询快速加载双向关系?事实上,如果检索到 N 个子实例,则执行 N+1 个查询。

最佳答案

正如所指出的here ,解决方案是使用非拥有方。如果您修改映射,将拥有方移动到父级(为简洁起见,字段包 protected ):

@Entity
public class Parent {
@Id Long id;
@OneToOne(fetch=FetchType.LAZY)
@JoinColumn(name="CHILD_ID")
Child child;
}

@Entity
public class Child {
@Id Long id;
@OneToOne(mappedBy="child",fetch=FetchType.EAGER)
Parent parent;
}

然后您可以查询生成单个选择的子项,因为有一个 FK 列:

@Test
public void shouldQueryTheDatabaseOnlyOnce() {
EntityManagerFactory emf = Persistence.createEntityManagerFactory("stackoverflow");
EntityManager entityManager = emf.createEntityManager();
Child child = entityManager.find(Child.class, 2l);
assertEquals((Long)1l, child.parent.id);
}

结果是:

Hibernate: select parent0_.id as id1_1_0_, child1_.id as id1_0_1_, child1_.PARENT_ID as PARENT_I2_0_1_ from Parent parent0_ left outer join Child child1_ on parent0_.id=child1_.PARENT_ID where parent0_.id=?

关于如果定义了双向关系,Hibernate 会执行两次相同的查询,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29125588/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com