Java 禁用休眠';s递归提取
当前堆栈:Java 禁用休眠';s递归提取,java,spring,hibernate,jpa,fetching-strategy,Java,Spring,Hibernate,Jpa,Fetching Strategy,当前堆栈: 弹簧靴1.5.1 Spring数据JPA1.11.0 Hibernate核心5.2.6 假设我们有以下@实体结构 @Entity class Root { @Id private Long id; @OneToMany @JoinColumn(name = "root_id") private Set<Child> children } @Entity class Child { @Id private
- 弹簧靴1.5.1
- Spring数据JPA1.11.0
- Hibernate核心5.2.6
@实体
结构
@Entity
class Root {
@Id
private Long id;
@OneToMany
@JoinColumn(name = "root_id")
private Set<Child> children
}
@Entity
class Child {
@Id
private Long id;
@OneToMany
@JoinColumn(name = "child_id")
private Set<Grandchild> grandchildren;
}
@Entity
class Grandchild {
@Id
private Long id;
}
如果集合是Set
s
public void test() {
List<Root> all = repo.findAll(); // SELECT root0_.* FROM root root0_
all.forEach(root -> {
System.out.println(root.getChildren() == null); // false
System.out.println(Hibernate.isInitialized(root.getChildren())); // false
root.getChildren().forEach(child -> {
// SELECT child0_.* FROM children child0_
// SELECT grandchild0_.* FROM grandchildren grandchild0_
System.out.println(child.getGrandchildren() == null); // false
System.out.println(Hibernate.isInitialized(child.getGrandchildren())); // true
child.getGrandChildren().forEach(grandchild -> {});
});
});
}
我是一个可以证明的白痴
我使用Lombok为我的POJO生成getter/setter等,它的默认实现
@EqualsAndHashCode
注释生成这两种方法,并考虑每个字段。。包括子集合。我很惊讶Root的子集合实际上是空的
它在您的情况下的工作方式(请仔细检查子项是否实际设置为null)是,当您访问getChildren()时(例如,通过对其调用size())。。该集合连同其所有急切依赖项一起从数据库中获取
所有的延迟依赖项(在这个特殊情况下是孙子)都被实例化为代理对象,但是不应该在数据库上对这些对象执行sql查询(请检查)
另外
这件事从来没有发生在我身上,只是一件值得记住的小事。。根据JPA,延迟加载特性只是持久性提供者的一个提示。即使将fetchType设置为LAZY,或者通常您希望在默认情况下延迟加载集合依赖项(这可以在配置会话工厂时完成),实现仍可能决定执行即时获取:
定义从数据库获取数据的策略。渴望的
策略是持久性提供程序运行时的一项要求
必须急切地获取数据。懒惰策略是对
持久性提供程序运行时,在
首先访问它。允许实现急切地获取
已为其指定惰性策略提示的数据
即使这是默认行为,也应该在
@OneToMany
注释中明确添加值fetch=FetchType.LAZY
。这可能有助于避免这种递归抓取实际上是否有对数据库的调用。。或者集合是作为代理创建的,没有任何调用吗?私有集子项
将永远不会为空。您是如何加载这些实例的?@AlanHay实际上它不是null
,我说错了。所以解决方案是使用没有子集合的equals和hashcode?实际上它不是null
,我说错了。我还更新了我的原始问题,提供了一些有关查询以及查询执行时间的信息。是的。。现在有道理了。。它已针对集合进行了初始化,因为当您添加到集合时,java会调用equals和hashCode方法(列表不是这种情况)。。你的案子很好。。
public void test() {
List<Root> all = repo.findAll(); // SELECT root0_.* FROM root root0_
all.forEach(root -> {
System.out.println(root.getChildren() == null); // false
System.out.println(Hibernate.isInitialized(root.getChildren())); // false
root.getChildren().forEach(child -> {
// SELECT child0_.* FROM children child0_
// SELECT grandchild0_.* FROM grandchildren grandchild0_
System.out.println(child.getGrandchildren() == null); // false
System.out.println(Hibernate.isInitialized(child.getGrandchildren())); // true
child.getGrandChildren().forEach(grandchild -> {});
});
});
}
public void test() {
List<Root> all = repo.findAll(); // SELECT root0_.* FROM root root0_
all.forEach(root -> {
System.out.println(root.getChildren() == null); // false
System.out.println(Hibernate.isInitialized(root.getChildren())); // false
root.getChildren().forEach(child -> {
// SELECT child0_.* FROM children child0_
System.out.println(child.getGrandchildren() == null); // false
System.out.println(Hibernate.isInitialized(child.getGrandchildren())); // false
child.getGrandChildren().forEach(grandchild -> {
// SELECT grandchild0_.* FROM grandchildren grandchild0_
});
});
});
}