我在stackoverflow上发现了很多次此问题,但是它们都没有给我明确的答案。为了简单起见,只有两张表将电影和语言绑定为一种关系。一切都按照Netbeans Hibernate DVD Store tutorial完成。现在,如何以首页(index.xhtml)语言显示。看起来非常简单。只需添加:

                  <h:column>
                    <f:facet name="header">
                        <h:outputText value="Language"/>
                    </f:facet>
                    <h:outputText value="#{item.languageByLanguageId.langName}"/>
                 </h:column>


(表语言名称中的逗号已在langName上重命名)
但是它仍然发出相同的LazyInitializationException异常。我尝试获取languageId,在这种情况下,我成功了。这意味着#{item.languageByLanguageId.langName}给出了异常,但#{item.languageByLanguageId.languageId}没有给出异常。它很奇怪。那么,当我可以根据我的语言ID使用显式提取时会发生什么情况。

所以我在FilmController.java方法中添加了获取语言的方法:

  public String getLanguageById(Integer langId) {
    String language = helper.getLangById(langId);
    return language;
  }


在FilmHelper.java(最终版本)中:

  public Film getFilmById(int filmId) {

Film film = null;

try {
    session = HibernateUtil.getSessionFactory().getCurrentSession();
    org.hibernate.Transaction tx = session.beginTransaction();
    Query q = session.createQuery("select count(film.filmId) from Film as film where film.filmId = :filmId");
    q.setParameter("filmId", filmId);
    Number count = (Number) q.uniqueResult();
    if (count.intValue() > 0)
      film = (Film) session.load(Film.class, filmId);
    tx.commit();
} catch (Exception e) {
    e.printStackTrace();
}

return film;


}

是的,它可以工作,我可以获取语言名称来修改index.xhtml:

<h:outputText value="{filmController.getLanguageById(item.languageByLanguageId.languageId)}"/>


比我尝试修改FilmActor.hbm.xml来添加lazy =“ false”并在index.xhtml(“#{item.languageByLanguageId.langName}”)中使用原点简单解决方案:

<many-to-one name="languageByOriginalLanguageId" class="dvdrental.Language" lazy="false" fetch="select">
        <column name="original_language_id" />
    </many-to-one>


再次正常工作。即使我设置了lazy =“ proxy”或lazy =“ no proxy”。但是我还是不明白如何使用默认属性lazy =“ true”。如果我尝试将整个文档保留在一个会话中(不要提交,这将导致会话结束),则存在另一个异常问题。看起来,lazy =“ true”在任何时候都不会达到正确的结果。

最佳答案

通过设置lazy=true属性,您可以让休眠状态延迟关联检索。因此,当您禁用lazy=false时,休眠状态将在检索父实例后立即执行其获取方法。如果设置fetch="join",将解决您的问题。


联接获取:Hibernate检索关联的实例或
使用OUTER JOIN在同一SELECT中收集。


你的例子;

<many-to-one name="languageByOriginalLanguageId" class="dvdrental.Language" fetch="join">
        <column name="original_language_id" />
</many-to-one>


您可以分别将fetch和lazy视为如何和何时。在您的示例中,lazy=false解决了您的问题,但是仍然执行了两个查询,因为您的fetch方法是select
Hibernate Fetching Strategies

更新

一旦对象被延迟初始化,您就只有实体的属性和延迟初始化的关联(只有ID)。然后将该对象传递给进一步对象(已提交事务),并且您想使用惰性初始化的关联之一(在您的情况下为Language)并获得异常。发生这种情况是因为您正在访问惰性对象,并且您的事务已经提交,所以休眠状态希望执行第二个查询而没有成功(fetch =“ select”)。可以通过将读取关联的代码移到提交事务之前来解决此问题。

当对象被分离并且当前会话关闭时,您必须执行

Hibernate.initialize(entity)


将您的分离实体分配给另一个会话。

10-08 08:42