【问题标题】:Hibernate reloading entities in a fetch joinHibernate 在 fetch 连接中重新加载实体
【发布时间】:2017-03-28 12:15:59
【问题描述】:

我在 Hibernate 重新加载查询中的实体时遇到问题,即使它们是作为主查询的一部分获取的。

实体如下(简体)

class Data {
    @Id
    String guid;

    @ManyToOne(fetch = FetchType.LAZY)
    @NotFound(action = NotFoundAction.IGNORE)
    DataContents contents; 
}

class DataClosure {
    @Id
    @ManyToOne(fetch = FetchType.EAGER)
    @Fetch(FetchMode.JOIN)
    @JoinColumn(name = "ancestor_id", nullable = false)
    private Data ancestor;

    @Id
    @ManyToOne(fetch = FetchType.EAGER)
    @Fetch(FetchMode.JOIN)
    @JoinColumn(name = "descendant_id", nullable = false)
    private Data descendant;

    private int length;
}

这是对父/子关系的闭包表建模。

我设置了一些标准如下

    final Criteria criteria = getSession()
            .createCriteria(DataClosure.class, "dc");
    criteria.createAlias("dc", "a");
    criteria.createAlias("dc.descendant", "d");
    criteria.setFetchMode("a", FetchMode.JOIN);
    criteria.setFetchMode("d", FetchMode.JOIN);
    criteria.add(Restrictions.eq("d.metadataGuid",guidParameter));
    criteria.add(Restrictions.ne("a.metadataGuid",guidParameter));

这会产生以下 SQL 查询

select
    this_.descendant_id as descenda2_21_2_,
    this_.ancestor_id as ancestor3_21_2_,
    this_.length as length1_21_2_,
    d2_.guid as metadata1_20_0_,
    d2_.name as name5_20_0_,
    a1_.guid as metadata1_20_1_,
    a1_.name as name6_20_1_
from
    data_closure this_ 
inner join
    data d2_ 
        on this_.descendant_id=d2_.metadata_guid 
inner join
    data a1_ 
        on this_.ancestor_id=a1_.metadata_guid 
where
    d2_.guid=? 
    and a1_.guid<>?

看起来它正在正确实现连接提取。但是当我执行时

    List list = criteria.list();

我在结果集中的每一行的 SQL 日志中看到这些条目之一

Result set row: 0
DEBUG Loader  - Loading entity: [Data#testGuid19]
DEBUG SQL  - 
select
    data0_.guid as guid1_20_0_,
    data0_.title as title5_20_0_,
from
    data data0_ 
where
    data0_.guid=?
Hibernate: 
   (omitted)
DEBUG Loader  - Result set row: 0
DEBUG Loader  - Result row: EntityKey[Data#testGuid19]
DEBUG TwoPhaseLoad  - Resolving associations for [Data#testGuid19]
DEBUG Loader  - Loading entity: [DataContents#7F1134F890A446BBB47F3EB64C1CF668]
DEBUG SQL  - 
select
    dataContents0_.guid as guid_12_0_,
    dataContents0_.isoCreationDate as isoCreat2_12_0_,
from
    dataContents dataContents0_ 
where
    dataContents0_.guid=?
Hibernate: 
    (omitted)

看起来即使 DataContents 被标记为延迟加载,它也被急切地加载。

所以我要么想在我的查询中以某种方式获取连接 DataClosure 和 Data 并懒惰地获取 DataContents,或者如果无法获取连接 DataContents。

编辑:

像这样对闭包表进行建模

class DataClosure {
    @Id
    @Column(name = "ancestor_id", nullable = false, length =36 )
    private String ancestorId;

    @Id
    @Column(name = "descendant_id", nullable = false, length =36 )
    private String descendantId;

    @ManyToOne(fetch = FetchType.EAGER)
    @Fetch(FetchMode.JOIN)
    @JoinColumn(name = "ancestor_id", nullable = false)
    private Data ancestor;

    @ManyToOne(fetch = FetchType.EAGER)
    @Fetch(FetchMode.JOIN)
    @JoinColumn(name = "descendant_id", nullable = false)
    private Data descendant;

    private int length;
}

解决了这个问题。换句话说,在其他表的实体上使用@Id 注释似乎会导致问题,即使生成的查询没有任何问题。

【问题讨论】:

  • 你确定你的代码没有触发DataContents的加载?
  • 是的,我只是在调用 list() 方法之前和之后的断点处执行此操作,所以我的代码还没有机会做任何事情。

标签: java hibernate join


【解决方案1】:

我认为你的问题可能是这样的

@NotFound(action = NotFoundAction.IGNORE)

有大量的谷歌搜索结果表明,使用它会导致延迟加载变得急切。我认为这是 Hibernate 中的一个错误。

将此添加到注释列表应该可以解决问题

@LazyToOne(value=LazyToOneOption.NO_PROXY)

因为这会通知 Hibernate,您以后不会尝试使用该属性,因此不需要代理。

【讨论】:

  • 这几乎奏效了,它减少了很多对 DataContents 的查询,但我仍然得到每个 Data 实体的一个查询,这应该是通过 fetch 连接加载的。
  • 你能确认 NotFound 注释是原因吗?所以如果你完全删除它会发生什么?
  • 我不确定。我实际上已经简化了实体模型,因此我已经摆脱了 DataContents 实体,并且我现在只有一个常规列(字符串类型)。我仍然为每个返回的行获取一个 Data 实体查询,即使连接查询正在正确执行。
  • 我想通了 - 这是我使用的 @Id 列。它是一个实体,因此出于某种原因,Hibernate 不会接受它作为 fetch join 候选者。我将编辑我的问题以显示解决方案。
  • 哦。很高兴您能够解决它,但这似乎又像一些不应该存在的 Hibernate 怪癖:)
猜你喜欢
  • 2014-04-14
  • 2012-03-16
  • 2023-04-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多