hibernate: LazyInitializationException: не удалось инициализировать прокси-сервер

Вот один из них, который меня озадачил. Я пытаюсь реализовать базовую структуру DAB 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) 

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

     session.update(object); 

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

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

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

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

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

    и т. д. Это лишь один пример того, что может пойти не так.
    –Тим Сабин

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

    если вы используете Lazy loading, ваш метод должен быть аннотирован с помощью

    @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW) для сеанса @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW) EJB

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

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

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

         

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

    Жизнь хороша … 🙂

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

    • если вы используете конфигурацию XML: добавьте default-lazy="false" в элемент
    • если вы используете конфигурацию аннотаций: добавьте @Proxy(lazy=false) в свой class (ы)

    Кажется, только ваш 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 (объект);

    Если вы вручную управляете сеансом Hibernate, вы можете посмотреть здесь sessionFactory.getCurrentSession () и связанные с ним документы:

    http://www.hibernate.org/hib_docs/v3/reference/en/html/architecture-current-session.html

    Я думаю, что Piko означает в своем ответе, что есть файл hbm. У меня есть файл Tax.java. Информация о сопоставлении сохраняется в файле hbm (= hibernate mapping). В теге class есть свойство lazy . Установите для этого свойства значение true. Следующий пример hbm показывает способ установить для ленивого свойства значение false .

    `id … ‘

    Если вы используете Annotations вместо этого, посмотрите в hibernate documenation. http://docs.jboss.org/hibernate/stable/annotations/reference/en/html_single/

    Надеюсь, это помогло.

    использовать Hibernate.initialize для ленивого поля

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

     @PersistenceContext 

    в

     @PersistenceContext(type = PersistenceContextType.EXTENDED) 

    По умолчанию все ассоциации « one-to-many и « many-to-many получают лениво при первом доступе.

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

     transactionTemplate.execute(new TransactionCallback() { @Override public Void doInTransaction(TransactionStatus transactionStatus) { 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() ) ); return null; } }); 

    Другим вариантом является получение всех ассоциаций LAZY при загрузке вашего объекта, чтобы:

     SecurityFiling sf2 = sfdao.read( sf.getId() ); 

    должен также получить LAZY submissionType :

     select sf from SecurityFiling sf left join fetch.sf.submissionType 

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

    Вы можете получить столько [one|many]-to-one ассоциаций и [one|many]-to-one ассоциацию «[one | many] -to-many» (из-за работы с декартовым продуктом).

    Чтобы инициализировать несколько «[one | many] -to-many», вы должны использовать Hibernate.initialize (collection) сразу после загрузки вашего корневого объекта.

    Давайте будем гением компьютера.