双向 OneToOne 被多次加载

Bidirectional OneToOne gets Loaded multiple Times

我有两个实体通过双向 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 数据和 CRUDRepository 来使用生成的查询加载父项,例如 Parent findByBusinessKey(String businessKey) 因为默认的 FetchMode 是 Eager,所以子实体通过其在父 Table 中的 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 父实体已经存在并且不需要提取?我在 Child 实体中尝试了 optional=false,但它没有帮助。

版本

我目前正在使用 hibernate 5.2.12 和 Spring Boot 1.2.8。不幸的是,版本更新目前不是一个选项。此外,即使数据库方面的更改仍然是可能的,也需要在其他地方进行相对较大的重构工作。 我只需要告诉 hibernate 不要急切地从 Db 中获取父引用。也许 EntityGraph 可以帮助解决这个问题,但我还没有使用过它们,现在也不太了解它。

另见

感谢任何帮助

@OneToOne 映射就是这种情况。我去过那里,做过那件事。要通过它,您必须在 Hibernate 脏检查机制上实现字节码增强,并更改父端不使用代理(注释:@LazyToOne(LazyToOneOption.NO_PROXY))。

请参考Vlad Mihalcea's article describing exactly your case I think

在那篇文章中,您还将找到 link 另一篇有用的 Vlad 文章 - 有关如何实现字节码增强的信息