2014-09-21 3 views
0

Я нашел много раз в stackoverflow этой проблеме, но ничто из них не дает мне четкого ответа. Для простоты есть только две таблицы фильм и язык связанный много к одному отношение. Все сделано согласно Netbeans Hibernate DVD Store tutorial. Теперь, как отобразить на первой странице (index.xhtml) язык. Это выглядит очень просто. Просто добавьте:Проблема с гибернацией: org.hibernate.LazyInitializationException: не удалось инициализировать прокси - нет сеанса

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

(Comumn в таблице языкаимя было переименовано в 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 добавить ленивым = "ложь" и использовать происхождение простое решение в 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" не отвечает в подходящий момент времени.

ответ

1

С настройкой атрибута lazy=true вы позволяете спящему режиму задерживать извлечение ассоциации. Поэтому, когда вы отключите lazy=false, hibernate немедленно выполнит свой метод выборки сразу после получения родительского экземпляра. Ваша проблема будет решена, если вы установите fetch="join".

Регистрация выборки: Hibernate возвращает соответствующий экземпляр или коллекции в том же SELECT, используя OUTER JOIN.

Ваш пример;

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

Вы можете посмотреть на выбор и ленив, как и когда, соответственно. В вашем примере lazy=false решил вашу проблему, но все еще два запроса, где было сделано, потому что ваш метод fetch был select. Hibernate Fetching Strategies

UPDATE

Однажды, когда объект ленив инициализирован, то есть только свойства вашей сущности и ленивой инициализирован ассоциации (только ид у вас есть). Затем этот объект передается для дальнейшего использования (транзакция уже используется), и вы хотите использовать одну из ленивых инициализированных ассоциаций (в вашем случае Язык) и получили исключение. Это происходит потому, что вы обращаетесь к ленивому объекту, и ваша транзакция уже совершена, поэтому hibernate хочет выполнить ваш второй запрос без успеха (fetch = "select"). Это можно устранить, перемещая код, который считывает ассоциацию непосредственно перед транзакцией.

Когда объект отсоединяется и текущая сессия закрыта, то вы должны сделать

Hibernate.initialize(entity) 

назначить свой отдельностоящий объект на другую сессию.

0

Благодарим вас за разъяснение. Я проверил ваш совет. Он работает, и я полагаю, что соединение должно быть быстрее, чем два разных выбора (это зависит от индексов, оптимизатора и т. Д.), Но все же, когда я пытаюсь использовать комбинацию lazy = "true" и fetch = "join" it again не удается:

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

Даже если исключение отличается, до сих пор нет Сукчес:

java.lang.ExceptionInInitializerError 
    at controller.HibernateUtil.<clinit>(HibernateUtil.java:30) 

Тем не менее, должны быть четко разъяснены три способа, как избежать проблем с неисполнением или явной ленивым = «истинный» ,

Смежные вопросы

 Смежные вопросы