hibernate: LazyInitializationException: не удалось инициализировать прокси - PullRequest
69 голосов
/ 06 декабря 2008

Вот тот, который меня озадачил. Я пытаюсь реализовать базовую структуру DAO Hibernate, но у меня возникла проблема.

Вот необходимый код:

int startingCount = sfdao.count();
sfdao.create( sf );
SecurityFiling sf2 = sfdao.read( sf.getId() );
sfdao.delete( sf );
int endingCount = sfdao.count();

assertTrue( startingCount == endingCount );
assertTrue( sf.getId().longValue() == sf2.getId().longValue() );
assertTrue( sf.getSfSubmissionType().equals( sf2.getSfSubmissionType() ) );
assertTrue( sf.getSfTransactionNumber().equals( sf2.getSfTransactionNumber() ) );

Ошибка на третьем assertTrue, где он пытается сравнить значение в sf с соответствующим значением в sf2. Вот исключение:

org.hibernate.LazyInitializationException: could not initialize proxy - no Session
    at org.hibernate.proxy.AbstractLazyInitializer.initialize(AbstractLazyInitializer.java:86)
    at org.hibernate.proxy.AbstractLazyInitializer.getImplementation(AbstractLazyInitializer.java:140)
    at org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer.invoke(JavassistLazyInitializer.java:190)
    at com.freightgate.domain.SecurityFiling_$$_javassist_7.getSfSubmissionType(SecurityFiling_$$_javassist_7.java)
    at com.freightgate.dao.SecurityFilingTest.test(SecurityFilingTest.java:73)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:40)

Ответы [ 14 ]

68 голосов
/ 03 сентября 2010

Проблема в том, что вы пытаетесь получить доступ к коллекции в объекте, который отсоединен . Вам необходимо повторно прикрепить объект перед доступом к коллекции в текущем сеансе. Вы можете сделать это через

session.update(object);

Использование lazy=false не является хорошим решением, поскольку вы отказываетесь от функции отложенной инициализации в режиме гибернации. Когда lazy=false, коллекция загружается в память одновременно с запросом объекта. Это означает, что если у нас есть коллекция из 1000 элементов, все они будут загружены в память, несмотря на то, что мы собираемся обращаться к ним или нет. И это не хорошо.

Пожалуйста, прочитайте эту статью , где объясняется проблема, возможные решения и почему она реализована таким образом. Кроме того, чтобы понять сеансы и транзакции, вы должны прочитать эту другую статью .

14 голосов
/ 06 декабря 2008

Обычно это означает, что сеанс Hibernate-владельца уже закрыт. Вы можете сделать одно из следующих действий, чтобы исправить это:

  1. Какой бы объект не создавал эту проблему, используйте HibernateTemplate.initialize(object name)
  2. Используйте lazy=false в ваших файлах hbm.
11 голосов
/ 16 февраля 2011

Смотрите мою статью. У меня была та же проблема - LazyInitializationException - и вот ответ, который я, наконец, придумал:
http://community.jboss.org/wiki/LazyInitializationExceptionovercome
Установка lazy = false - это не ответ - он может загрузить все сразу, и это не обязательно хорошо. Пример:
1 таблица записей A ссылки:
5 записей таблицы B ссылок:
25 записей таблицы C ссылок:
125 записей таблицы D
...
и т.д. Это всего лишь один пример того, что может пойти не так.
- Тим Сабин

7 голосов
/ 26 сентября 2010

Если вы используете спящий режим с аннотациями JPA, это будет полезно. В вашем классе обслуживания должен быть установщик для менеджера сущностей с @PersistenceContext. измените это на @PersistenceContext (type = PersistenceContextType.EXTENDED). Тогда вы можете получить доступ к ленивой собственности в любом месте.

4 голосов
/ 16 августа 2010

если вы используете отложенную загрузку, ваш метод должен быть помечен

@TransactionAttribute(TransactionAttributeType.REQUIRES_NEW) для сеанса без сохранения состояния EJB

3 голосов
/ 03 сентября 2010

Мы также столкнулись с этой ошибкой. Чтобы решить эту проблему, мы добавили lazy = false в файл отображения Hibernate.

Похоже, у нас был класс A, который находится внутри сеанса, который загружает другой класс B. Мы пытаемся получить доступ к данным класса B, но этот класс B отсоединен от сеанса.

Чтобы получить доступ к этому классу B, нам пришлось указать в файле отображения Hibernate класса A атрибут lazy = false. Например,

     <many-to-one name="classA" 
                 class="classB"
                 lazy="false">
        <column name="classb_id"
                sql-type="bigint(10)" 
                not-null="true"/>
    </many-to-one>  
2 голосов
/ 03 мая 2012

Кажется, только ваш DAO использует сессию. Таким образом, новый сеанс открывается, а затем закрывается для каждого вызова метода DAO. Таким образом, выполнение программы может быть возобновлено как:

// open a session, get the number of entity and close the session
int startingCount = sfdao.count();

// open a session, create a new entity and close the session
sfdao.create( sf );

// open a session, read an entity and close the session
SecurityFiling sf2 = sfdao.read( sf.getId() );

// open a session, delete an entity and close the session
sfdao.delete( sf );

etc...

По умолчанию сбор и сопоставление в объекте ленивы: они загружаются из базы данных по требованию. Таким образом:

sf.getSfSubmissionType().equals( sf2.getSfSubmissionType() )

выдает исключение, потому что запрашивает новую загрузку из базы данных, а сеанс, связанный с загрузкой объекта, уже закрыт.

Существует два подхода к решению этой проблемы:

  • создать сессию, чтобы заключить весь наш код. Таким образом, это будет означать изменение вашего контента DAO, чтобы избежать открытия второго сеанса

  • создайте сеанс, а затем обновите (то есть повторно подключите) вашу сущность к этому сеансу перед утверждениями.

    Session.update (объект);

2 голосов
/ 04 ноября 2010

Если вы знаете о влиянии lazy=false и по-прежнему хотите использовать его по умолчанию (например, для целей создания прототипов), вы можете использовать любое из следующего:

  • если вы используете конфигурацию XML: добавьте default-lazy="false" к вашему <hibernate-mapping> элементу
  • если вы используете конфигурацию аннотации: добавьте @Proxy(lazy=false) к вашему классу (ам) сущности
2 голосов
/ 08 января 2009

Хорошо, наконец-то понял, где я был упущен. У меня было ошибочное мнение, что я должен обернуть каждый метод DAO в транзакцию. Ужасно неправильно! Я усвоил свой урок. Я вытащил весь код транзакции из всех методов DAO и настроил транзакции строго на уровне приложения / менеджера. Это полностью решило все мои проблемы. Данные должным образом загружаются по мере необходимости, упаковываются и закрываются после выполнения коммита.

Жизнь прекрасна ...:)

1 голос
/ 19 июня 2015

Если вы используете аннотации Spring и JPA, самый простой способ избежать проблем с сеансом при отложенной инициализации - это повтор:

@PersistenceContext   

до

@PersistenceContext(type = PersistenceContextType.EXTENDED)
...