我在 hibernate 中遇到了一个棘手的问题,它使用的查询数量超出了简单 findAll 调用所需的数量。在我的模型中,有两个实体 Parent 和 Child 具有 oneToMany 关联;
父级
class Parent{
@id
private long id;
//unique
private String code;
@OneToMany(mappedBy = "parent", cascade = CascadeType.ALL)
private List<OperatorAttribute> children;
}
child
class Child{
@id
private long id;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "parent_code", referencedColumnName = "code")
@LazyToOne(LazyToOneOption.NO_PROXY) // here i'm trying to tell hibernate to create no proxy and just ignore the field but no luck :/
public Parent parent;
}
问题是,每当我尝试使用 childRepository.findAll()
从数据库中获取子列表时,hibernate 都会进行 N+1 选择查询,为什么?
我认为这可能是对此的解释:恕我直言,当 Hibernate 填充子对象时,他尝试为父字段创建代理,
为此,他需要父行的 id,该 id 通常应该是子表中的外键,但在我的情况下,#fk
并未绑定(bind)到 Parent
表的主键,而是绑定(bind)到一个唯一列(请不要问我为什么),因此为了填充 id,他需要执行额外的选择查询来初始化父字段的代理。
所以我的问题是如何阻止 Hibernate 为父字段创建代理。
谢谢。
最佳答案
你是对的。代理需要被代理实体的@Id
(这样可以确保可以找到它)。一旦定义了LazyToOneOption.NO_PROXY
,它就会告诉系统 give back the real object 。这就是这里发生的事情。您在结果上映射的不是代理,因为使用此注释您显式禁用了它,因此您必须获取真实的对象。
根据所提供的映射,您不能忽略该字段,因为您将丢失 Child
上的 Parent
的信息。因此,通过这种设置,您始终需要读取父级
。
如果在特定区域中根本不需要此字段,您可以创建一些到同一表的其他映射。不过要小心!这可能会引入大量其他与缓存相关的问题。
关于java - 如何防止hibernate创建代理,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44197466/