禁用Hibernate的递归提取

时间:2017-02-08 15:12:05

标签: java spring hibernate jpa fetching-strategy

当前筹码:

  • Spring Boot 1.5.1
  • Spring Data JPA 1.11.0
  • Hibernate Core 5.2.6

假设我们有以下@Entity结构

@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;
}

当我查询所有/特定Root个对象时,Hibernate只从相应的表中选择并且生成的对象'children Set是 null 一个Hibernate代理 - 应该如此。

当我调用getChildren()时,Hibernate正确初始化集合,但也(无根据)提取每个Child对象的grandchildren集。

有人可以解释为什么会发生这种递归提取并且有没有办法禁用它?

我做了一些挖掘,这就是我提出的:它似乎与Hibernate映射@OneToMany的方式有关,具体取决于目标集合是List还是{{1} }。

Set

如果集合是private final RootRepo repo; s

Set

然而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 -> {}); }); }); } s

List

我是一名可认证的白痴。

我正在使用Lombok为我的 POJO 生成getter / setter等,其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_ }); }); }); } 注释的默认实现会生成考虑每个字段的两种方法..包括子集合

1 个答案:

答案 0 :(得分:0)

我很惊讶Root的孩子实际上是空的。

它在你的情况下的工作方式(请仔细检查子项是否实际设置为null),是当你访问getChildren()时(例如通过调用size())..那个集合被获取来自数据库及其所有渴望的依赖项。

所有延迟依赖项(在这种特殊情况下都是孙子)都被实例化为Proxy对象,但是对于那些应该没有对数据库执行sql查询(请检查)。

<强>另外

它从来没有发生在我身上,但只是要记住一点......根据JPA,延迟加载功能只是对持久性提供程序的提示。即使您将fetchType设置为LAZY,或者通常您希望默认情况下延迟加载您的集合依赖项(可以在配置会话工厂时完成),实现仍可能决定执行EAGER提取:

  

定义从数据库中获取数据的策略。 EAGER   策略是持久性提供程序运行时的要求   必须急切地获取数据。 LAZY策略是一个提示   持久性提供程序运行时,应该在延迟时获取数据   它是第一次访问。允许实施急切地获取   已指定LAZY策略提示的数据。