【问题标题】:Why does the JPA merge operation cause multiple selects before update?为什么JPA合并操作会导致更新前多选?
【发布时间】:2019-02-16 16:42:25
【问题描述】:

我们在 Hibernate 5.x 中使用 Spring Data 存储库

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

@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() 调用,该调用在从分离的对象复制状态更改之前从数据库中获取对象图。

我有两个问题:

  1. 为什么 hibernate 不能像使用 fetchgraph 时那样将这些语句加入到一个大选择中?

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

谢谢

【问题讨论】:

    标签: java hibernate jpa merge orm


    【解决方案1】:

    我对你的情况也有类似的问题,原因是在@OneToMany 关联上设置了级联CascadeType.ALL。更新和合并父实体会导致对子关联的大量选择。

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

    我通过减少级联的范围来解决我的问题,只有 PERSIST 和 REMOVE 就足够了

    @OneToMany(mappedBy = "fooBar", cascade = {CascadeType.PERSIST, CascadeType.REMOVE}, orphanRemoval = true)
    private Set<Foo> chassis = new HashSet<>(0);
    

    【讨论】:

      【解决方案2】:

      您可以使用session.update 而不是合并来解决此问题。

      Session session = entityManager.unwrap(Session.class);
      
      for (Post post: posts) {
          session.update(post);
      }
      

      【讨论】:

      • 我切换到 session.update()。现在我在调用 update 时仍然看到多个选择,然后我得到一个唯一约束异常。
      • 尝试调试它,看看为什么。除非您使用 select-before-update,否则选择可能来自其他部分。
      猜你喜欢
      • 2019-11-15
      • 1970-01-01
      • 2015-04-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-07-31
      相关资源
      最近更新 更多