为什么JPA合并操作会导致在更新之前进行多次选择?

时间:2018-09-12 06:02:25

标签: java hibernate jpa merge orm

我们正在将Spring Data存储库与Hibernate 5.x一起使用

我们有一个层次很深的实体图。 映射如下所示:

@Entity
public class FooBar {
    @OneToMany(mappedBy = "fooBar", cascade = CascadeType.ALL, orphanRemoval = true)
    private Set<Foo> chassis = new HashSet<>(0);

    ...
}

@Entity
public class Foo {

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "foobar_id")
    private FooBar fooBar;

    @OneToMany(mappedBy = "foo", cascade = CascadeType.ALL, orphanRemoval = true)
    private Set<Bar> chassis = new HashSet<>(0);

    ...
}

@Entity
public class Bar {
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "foo_id")
    private FooBar foo;

    ...
}

如您所见,FooBar实体具有一组Foo实体。每个Foo实体都包含更多的Bar实体,依此类推。

我们使用Fetchgraph功能将FooBar实体加载到运行时所需的关系中,以避免在获取惰性关联时出现n + 1个查询问题。 在调用服务以加载实体图之后,事务已结束并且实体已分离。

稍后在FooBar实体上调用save时,这将导致多个select语句。每个获取一个子实体。

我知道这是来自entitymanager merge()调用,该调用在从分离的对象复制状态更改之前从db获取对象图。

我有两个问题:

  1. 为什么休眠无法像使用fetchgraph时那样将这些语句加入一个大选择?

  2. 当我从关系中删除所有级联选项时,它仍然会导致多个选择,但只会更新顶部的FooBar实体的属性。为什么即使没有级联合并,hibernate仍然在合并期间获取所有已加载的子实体?

谢谢

1 个答案:

答案 0 :(得分:1)

this article中所述,您可以使用session.update而不是合并来解决此问题。

Session session = entityManager.unwrap( Session.class );

for ( Post post: posts ) {
    session.update( post );
}