java - 双向 OneToOne 被多次加载

标签 java spring-boot hibernate jpa one-to-one

我有两个实体通过这样的双向 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 但它没有帮助。

版本

我目前使用的是 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

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

关于java - 双向 OneToOne 被多次加载,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65307495/

相关文章:

java - 如何解决 '.class' 预期错误?

java - android 中每个月的本地通知

java - RabbitMQ队列消费行为

hibernate 使用条件更新单列

java - 这个Java程序是否需要是两个独立的文件

java - 如何访问 DrawerLayout 内的 TextView

Spring Boot 和 Hibernate 延迟初始化的奇怪行为

java - 应用程序执行时不使用 spring.cloud.config 的 application.yml 中的设置

java - Hibernate 的删除方法给出 StaleStateException

java - 每个用户在通过他/她的凭据登录时都有自己的列出的数据