【发布时间】:2021-03-26 04:23:52
【问题描述】:
我有两个通过双向 OneToOne 关联连接的实体,如下所示:
@Entity
class Parent {
@NotNull
String businessKey;
@OneToOne(cascade = CascadeType.ALL)
@JoinColumn(name = "child_id")
@JsonManagedReference
Child child;
}
@Entity
class Child {
@JsonBackReference
@OneToOne(mappedBy = "child", fetch = FetchType.LAZY)
Parent parent;
}
背景
我正在使用 Spring Data 和 CRUDRepository 使用生成的查询(如 Parent findByBusinessKey(String businessKey))加载父级
因为默认的 FetchMode 是 Eager,所以子实体通过父表中的 child_id 外键获取。 Eager fetching 在这里不是问题,因为整个图稍后会被序列化为 json。
最初该关联是单向的,并且 Child 没有引用其 Parent。不幸的是,必须添加反向引用并且性能极度下降。生成的 Sql 的日志显示以下查询(简化):
select p.id, p.business_key, ..., p.child_id from Parent p where p.business_key = ?;
select c.id, ... from Child c where c.id = ?;
-- here it goes wrong
select p.id, p.business_key, ... from Parent p
left join OtherEagerJoinedTable t on p.other_id = t.id
left join AnotherEagerJoinedTable a on p.another_id = a.id
where p.child_id = ?;
Hibernate 似乎从数据库中单独获取父对象,而不是使用已经选择的实例。对于每个像这样的 OneToOne 关系(有几个)都会发生这种情况,每个连接查询最多需要 200 毫秒。通过单向映射,整个实体图的查询时间不到 100 毫秒。
问题
我如何告诉 Hibernate 父实体已经存在并且不需要获取?我在子实体中尝试了optional=false,但没有帮助。
版本
我目前使用的是休眠 5.2.12 和 Spring Boot 1.2.8。不幸的是,版本更新目前不是一个选项。此外,即使 DB 端的更改仍然可能,它也需要在其他地方进行相对较大的重构工作。 我只需要告诉 hibernate 不要急于从 Db 获取父引用。也许 EntityGraph 可以帮助解决这个问题,但我还没有使用它们,现在也没有太多。
另见
- https://vladmihalcea.com/hibernate-facts-the-importance-of-fetch-strategy(结论部分提到了可选属性,但本例中的拥有方与我的情况相反)
- Hibernate performs twice the same query if a bidirectional relationship is defined
- one to one mapping using primary key join column
- How can I make a JPA OneToOne relation lazy
感谢任何帮助
【问题讨论】:
-
你没有提供足够的上下文。
-
您可以尝试添加
@JsonManagedReference和@JsonBackReference -
@SSK 这些已经存在于我的实际代码中,我在示例中添加了它们以澄清
标签: java spring-boot hibernate jpa one-to-one