我在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)
将您的分离实体分配给另一个会话。