我在 stackoverflow 上多次发现这个问题,但他们没有给我明确的答案。为了简单起见,只有两个表电影和语言绑定(bind)了多对一的关系。一切按照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} 没有。它很奇怪。那么,当我根据 languageId 使用显式获取(如果我可以获得它)时会发生什么。
所以我在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"。如果我尝试将整个文档保留在一个 session 中(不进行提交,这会导致 session 结束),则会出现另一个异常问题。看起来,lazy="true"在任何时候都无法达到正确的结果。
最佳答案
通过设置lazy=true
属性,您可以允许hibernate延迟关联检索。因此,当您禁用lazy=false时,hibernate将在检索父实例后立即执行其获取方法。如果你设置fetch="join"
,你的问题就会得到解决。
Join fetching: Hibernate retrieves the associated instance or collection in the same SELECT, using an OUTER JOIN.
你的例子;
<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)。然后该对象被传递以供进一步使用(事务已提交),并且您想要使用惰性初始化关联之一(在您的情况语言中)并得到异常。发生这种情况是因为您正在访问惰性对象并且您的事务已经提交,因此 hibernate 想要执行第二个查询但没有成功(fetch =“select”)。这可以通过将读取关联的代码移至事务提交之前来解决。
当你的对象被分离并且当前 session 关闭时,你必须这样做
Hibernate.initialize(entity)
将您的分离实体分配给另一个 session 。
关于java - Hibernate 问题 : org. hibernate.LazyInitializationException:无法初始化代理 - 无 session ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25962814/