当前位置: 首页 > 面试题库 >

强制休眠以热切加载多个关联而不更改映射

南宫阳冰
2023-03-14
问题内容

我有一些实体具有一对一的懒惰关系(为简洁起见,省略了逻辑):

@Entity
class A{
    @OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
    @JoinColumn(name = "a_pk", nullable = false)
    List<B> blist = new ArrayList<>();

    @OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
    @JoinColumn(name = "a_pk", nullable = false)
    List<C> clist = new ArrayList<>();

    @Column(name = "natural_identifier", nullable = false)
    private String id;
}

@Entity
class B{
}

@Entity
class C{
    @OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
    @JoinColumn(name = "c_pk", nullable = false)
    List<D> dlist = new ArrayList<>();

    @OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
    @JoinColumn(name = "c_pk", nullable = false)
    List<E> elist = new ArrayList<>();
}

@Entity
class D{
    @OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
    @JoinColumn(name = "d_pk", nullable = false)
    List<F> flist = new ArrayList<>();
}

@Entity
class E{
}

@Entity
class F{
}

在某些(非常罕见)的情况下,我想热切地加载A及其所有关联的实例。这样做的原因是我想对该A实例及其整个子实例进行一些修改,然后根据用户输入保存或丢弃它们。

如果要按需加载内容,则必须根据用户请求将实体重新附加到新的会话,但是这些实体正在被修改,并且修改不应持久化。

所以我写这样的东西:

Session session = sessionFactory.openSession();
s.beginTransaction();
Criteria c = session
                    .createCriteria(A.class)
                    .add(Restrictions.eq("id", someValue))
                    .setFetchMode("blist", SELECT)
                    .setFetchMode("clist", SELECT)
                    .createAlias("clist", "c")
                    .setFetchMode("c.dlist", SELECT)
                    .setFetchMode("c.elist", SELECT)
                    .createAlias("c.dlist", "d")
                    .setFetchMode("d.flist", SELECT);
A a = (A) c.uniqueResult();
session.close(); // line 150

a.getBlist().size(); // line 152 - debug
a.getClist().size(); // line 153 - debug

当我尝试访问内容时,出现以下异常line 152

org.hibernate.LazyInitializationException:
failed to lazily initialize a collection of role: 
A.blist, could not initialize proxy - no Session

如果将获取策略更改JOIN为条件中的所有位置,都会遇到相同的异常,但是会出现异常line 153(换句话说,第一个关联会被加载,而其他则不会加载)。

编辑:阿列克谢·马列夫(Alexey Malev)建议为别名设置获取模式; 这似乎是真的。符合以下条件:

Criteria c = session
                    .createCriteria(A.class)
                    .add(Restrictions.eq("id", someValue))
                    .setFetchMode("blist", JOIN)
                    .setFetchMode("clist", JOIN);

我收到一个不同的异常: org.hibernate.loader.MultipleBagFetchException: cannot simultaneously fetch multiple bags 在第149行。因此,无法进行join-fetching。

问题是,如何装载整个东西?

Hibernate 4.2.12版最终版


问题答案:

通过使用稍微不同的方法,我找到了解决原始问题的方法。引用Hibernate ORM文档:

有时,需要在关闭会话之前初始化代理或集合。例如,您可以通过调用cat.getSex()或cat.getKittens()。size()来强制初始化。但是,这可能会使代码的读者感到困惑,并且对于通用代码而言并不方便。

静态方法Hibernate.initialize()和Hibernate.isInitialized()为应用程序提供了一种处理延迟初始化的集合或代理的便捷方法。只要其Session仍处于打开状态,Hibernate.initialize(cat)将强制初始化代理cat。Hibernate.initialize(cat.getKittens())对于收集小猫具有类似的效果。

只是简单地获取延迟集合(a.getBlist())不会使其加载-
我最初犯了这个错误。如果我尝试从该集合中获取一些数据(获取项目,获取集合大小),它将加载。调用Hibernate.initialize(..)该集合将执行相同的操作。

因此,遍历实体关联及其各自的关联等,并Hibernate.initialize()在会话内明确初始化它们(例如使用),将在会话关闭后将所有内容加载到会话外可用。

使用该方法根本不使用条件提取模式(为什么它们不能按记录工作是另一个问题)。

这是N + 1问题的明显情况,但我可以接受。



 类似资料:
  • 我有几个具有惰性一对多关系的实体(为简洁起见省略了逻辑): 在某些情况下(非常罕见),我希望急切地加载A的实例及其所有关联。这样做的原因是,我想对该实例及其子实例整体进行一些修改,然后根据用户输入保存或丢弃它们。 如果我要根据需要加载东西,我必须根据用户请求将实体重新附加到新会话,但它们正在被修改,修改还不应该持久化。 所以我写了这样的东西: 当我尝试访问内容时,我在第 遇到异常: 如果我在条件中

  • 问题内容: 我有两个与多对多关联的表。 —数据库片段: 加载 ID 名称 会话 ID 日期 sessionsloads LoadId 的SessionID —hibernate映射片段: 为了从关联表 sessionloads中 删除一个条目,我执行以下代码: 但是,启动后,此代码将保持不变。 删除关联的正确方法是什么? 问题答案: 您需要更新和之间的链接的两端: 实际上,许多开发人员使用防御性方

  • 问题内容: 我的多对一映射存在性能问题。当我在日志文件中调试SQL查询时,可以进行主体查询,但是在我有其他表示多对一对象映射的查询之后。 Entity.hbm.xml: Object1.hbm.xml: Object2.hbm.xml: 查询HBM: 在pom.xml中 问题答案: 您是否尝试过像这样的FetchMode.SELECT?

  • 问题内容: 我这样做是为了对实体对象进行延迟加载: 我想与多个延迟加载的集合返回一个实体对象 加载的 ,我能做到这一点(通过在列表中,并设置超过联想单个标准是什么?): 问题答案: 是? 该文档包含以下内容: 该查询将通过外部联接获取伴侣和小猫。有关更多信息,请参见第20.1节“获取策略”。

  • 问题内容: 我有一个实体A,它具有-B实体,而B具有-A与@OneToOne双向关联。 现在,当我找到所有A记录时,hibernate使用B上的左外部联接执行两个查询,如下所示: 第一次查询会加载A和B字段,但可以,但是为什么要执行第二次查询来重新加载A?我认为此查询将B中的A内容加载,但此A显然是包含B的A …因此它已经加载了第一个查询,不是吗? -编辑- 实体A: 实体B: 就是这种情况,在A

  • 问题内容: 可以使用Hibernate标准吗? 问题答案: 我遇到了完全相同的问题,并且能够像这样解决它: 注:,和在上面的代码指在属性名,和类,相应地(类具有属性等)。 对于此解决方案,您甚至不需要在中设置和参数。