springboottest Hibernate: LazyInitializationException: Proxy konnte nicht initialisiert werden




springboottest org hibernate lazyinitializationexception could not initialize proxy no session (12)

Hier ist einer, der mich perplex hat. Ich versuche, eine grundlegende Hibernate-DAO-Struktur zu implementieren, habe aber ein Problem.

Hier ist der wesentliche Code:

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() ) );

Es schlägt auf dem dritten assertTrue fehl, wo es versucht, einen Wert in sf mit dem entsprechenden Wert in sf2 zu vergleichen. Hier ist die Ausnahme:

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)

Standardmäßig werden alle one-to-many und many-to-many Many many-to-many Zuordnungen beim erstmaligen Zugriff getrost abgerufen.

In Ihrem Anwendungsfall können Sie dieses Problem lösen, indem Sie alle DAO-Operationen in eine logische Transaktion einschließen:

transactionTemplate.execute(new TransactionCallback<Void>() {
    @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;
    }
});

Eine andere Möglichkeit besteht darin, alle LAZY-Assoziationen beim Laden Ihrer Entität abzurufen, damit:

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

sollte auch den LAZY-supplierType abrufen:

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

Auf diese Weise holen Sie eifrig alle faulen Eigenschaften und Sie können auf sie zugreifen, nachdem auch die Sitzung geschlossen wurde.

Sie können so viele [one|many]-to-one Zuordnungen und eine "[one | many] -to-many" Listenzuordnungen abrufen (weil ein kartesisches Produkt ausgeführt wird).

Um mehrere "[one | many] -to-many" zu initialisieren, sollten Sie Hibernate.initialize(collection) direkt nach dem Laden Ihrer root-Entity verwenden.



Verwenden Sie Hibernate.initialize für Lazy-Feld


Okay, endlich herausgefunden, wo ich nachlässig war. Ich hatte die falsche Vorstellung, dass ich jede DAO-Methode in eine Transaktion integrieren sollte. Schrecklich falsch! Ich habe meine Lektion gelernt. Ich habe den gesamten Transaktionscode von allen DAO-Methoden geholt und habe Transaktionen ausschließlich auf der Ebene der Anwendung / des Managers eingerichtet. Das hat meine Probleme vollständig gelöst. Die Daten werden ordnungsgemäß lazy geladen, wenn ich sie brauche, eingepackt und geschlossen, sobald ich das Commit mache.

Das Leben ist gut ... :)


Wir sind diesem Fehler ebenfalls begegnet. Was wir getan haben, um das Problem zu lösen, ist, dass wir in der Hibernate Mapping-Datei einen Lazy = False hinzugefügt haben.

Anscheinend hatten wir eine Klasse A innerhalb einer Sitzung, die eine andere Klasse B lädt. Wir versuchen, auf die Daten in Klasse B zuzugreifen, aber diese Klasse B ist von der Sitzung getrennt.

Damit wir auf diese Klasse B zugreifen können, mussten wir in der Hibernate-Zuordnungsdatei der Klasse A das Attribut lazy = false angeben. Beispielsweise,

     <many-to-one name="classA" 
                 class="classB"
                 lazy="false">
        <column name="classb_id"
                sql-type="bigint(10)" 
                not-null="true"/>
    </many-to-one>  

Ich denke, Piko meint in seiner Antwort, dass es die hbm-Datei gibt. Ich habe eine Datei namens Tax.java. Die Zuordnungsinformationen werden in der Datei hbm (= hibernate mapping) gespeichert. Im Klassen-Tag gibt es eine Eigenschaft namens faul . Setzen Sie diese Eigenschaft auf true. Das folgende HBM-Beispiel zeigt eine Möglichkeit, die faule Eigenschaft auf false zu setzen .

"Es ..."

Wenn Sie Annotationen verwenden, schauen Sie stattdessen in die Hibernation-Dokumentation. http://docs.jboss.org/hibernate/stable/annotations/reference/en/html_single/

Ich hoffe, das hat geholfen.


Siehe meinen Artikel. Ich hatte das gleiche Problem - LazyInitializationException - und hier ist die Antwort, die ich mir schließlich ausgedacht habe:
http://community.jboss.org/wiki/LazyInitializationExceptionovercome
Einstellung faul = falsch ist nicht die Antwort - es kann alles auf einmal laden, und das ist nicht unbedingt gut. Beispiel:
1 Datensatztabelle A Referenzen:
5 Datensätze Tabelle B Referenzen:
25 Datensätze Tabelle C Referenzen:
125 Datensätze Tabelle D
...
usw. Dies ist nur ein Beispiel dafür, was schiefgehen kann.
--Tim Sabin


Das Problem besteht darin, dass Sie versuchen, auf eine Auflistung in einem Objekt zuzugreifen, das getrennt ist. Sie müssen das Objekt erneut anfügen, bevor Sie auf die Sammlung für die aktuelle Sitzung zugreifen. Du kannst das durchmachen

session.update(object);

Die Verwendung von lazy=false ist keine gute Lösung, da Sie die Lazy Initialization-Funktion von hibernate wegwerfen. Wenn lazy=false , wird die Sammlung zur gleichen Zeit in den Speicher geladen, zu der das Objekt angefordert wird. Das heißt, wenn wir eine Sammlung mit 1000 Elementen haben, werden sie alle in den Speicher geladen, obwohl wir darauf zugreifen wollen oder nicht. Und das ist nicht gut.

Bitte lesen Sie diesen article in dem es das Problem erklärt, die möglichen Lösungen und warum es so umgesetzt wird. Um Sessions und Transaktionen zu verstehen, müssen Sie diesen anderen Artikel lesen.


Wenn Sie Hibernate mit JPA-Anmerkungen verwenden, ist dies nützlich. In Ihrer Serviceklasse sollte ein Setter für den Entity Manager mit @PersistenceContext vorhanden sein. Ändern Sie dies in @PersistenceContext (type = PersistenceContextType.EXTENDED). Dann können Sie in jedem beliebigen Bereich auf eine faule Eigenschaft zugreifen.


Es scheint nur Ihre DAO Sitzung verwenden. Daher ist eine neue Sitzung geöffnet und dann für jeden Aufruf einer DAO-Methode geschlossen. So kann die Ausführung des Programms wie folgt fortgesetzt werden:

// 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...

Standardmäßig sind Sammlung und Zuordnung in einer Entität faul: Sie werden bei Bedarf aus der Datenbank geladen. So:

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

löst eine Ausnahme aus, weil es ein neues Laden von der Datenbank anfordert und die mit dem Laden der Entität verknüpfte Sitzung wurde bereits geschlossen.

Es gibt zwei Ansätze, um dieses Problem zu lösen:

  • Erstellen Sie eine Sitzung, um unseren gesamten Code einzufügen. Das würde bedeuten, dass Sie Ihre DAO-Inhalte ändern müssen, um zu vermeiden, dass eine zweite Sitzung geöffnet wird

  • Erstellen Sie eine Sitzung und aktualisieren Sie dann Ihre Entität (dh verbinden Sie sie erneut) mit dieser Sitzung vor den Assertionen.

    session.update (Objekt);


Wenn Sie die Spring- und JPA-Annotation verwenden, ist das Replaysing der einfachste Weg, um ein Problem mit der Session in Faul Initialize zu vermeiden:

@PersistenceContext   

zu

@PersistenceContext(type = PersistenceContextType.EXTENDED)

Wenn Sie Lazy Loading verwenden, muss Ihre Methode mit kommentiert werden

@TransactionAttribute(TransactionAttributeType.REQUIRES_NEW) für Stateless Session EJB







lazy-evaluation