在 JPA + Hibernate 中使用单向 @ManyToOne 关系时,是否有办法避免 N+1 查询?

Ahm*_*hia 5 java spring hibernate jpa spring-data-jpa

我有以下实体:

虚拟A:

@Entity
@Table(name = "dummy_a")
@Data
public class DummyA implements Serializable {

private static final long serialVersionUID = 1L;

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;


@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "dummy_b_name", referencedColumnName = "name", updatable = false, insertable = false)
private DummyB dummyB;
}
Run Code Online (Sandbox Code Playgroud)

虚拟B:

@Entity
@Table(name = "dummy_b")
@Data
public class DummyB implements Serializable {

private static final long serialVersionUID = 1L;

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "entity_id")
private Integer id;

@Column(name = "name")
private String name;
}
Run Code Online (Sandbox Code Playgroud)

就目前而言,任何获取DummyA对象的尝试都会导致额外的查询来获取DummyB对象。由于 N+1 查询,这会导致不可接受的额外延迟,并且还会破坏Page返回的对象repository.findAll(specification, pageable),导致返回不正确的总页数和元素计数(在我的情况下为repositoryextends JpaRepository)。有没有办法做到这一点,以便延迟加载 DummyB 对象,或者,如果不可能,则可以在单个查询中急切地加载它们?

局限性:我对 JPA 和 Hibernate 相当陌生,并且一直在学习如何使用它们。我在正在从事的项目中遇到了以下情况。我没有自由包含新的依赖项,并且我的项目当前不允许通过@LazyToOne(LazyToOneOption.NO_PROXY).

到目前为止我已经尝试过但没有工作/没有按预期工作的事情:

  1. @ManyToOne(optinoal = false, fetch = FetchType.LAZY)
  2. 尝试通过删除 的setter 和 getter来查看访问dummyBin 中的字段dummyA是否导致 N+1 查询。dummyB仍然有N+1个查询。
  3. 使用@EntityGraphfindAll.
  4. 尝试实施PersistentAttributeInterceptable和使用PersistentAttributeInterceptor来解决问题。

到目前为止我查找过的资源链接:

  1. @ManyToOne(fetch = FetchType.LAZY) 不适用于非主键引用列
  2. JPA和Hibernate的N+1查询问题
  3. Hibernate 延迟加载用于反向一对一解决方法 - 这是如何工作的?
  4. 持久属性可拦截
  5. JPA 实体图

任何帮助是极大的赞赏。

Ahm*_*hia 1

如果有人好奇的话,我已经给出了答案。事实证明,某些条目在用作与DummyA关联的外键的列中具有无效的“魔术”值DummyB,导致 Hibernate 对这些空值执行单独的查询,以检查是否确实未找到关联(请参阅该文档相关问题的答案)。我把这些查询误认为是N+1。该项目还有一个拦截器,它扩展了 Hibernate 的拦截器,EmptyInterceptor以便修改生成页面的查询,从而在执行辅助查询时导致计数不正确。