webentwicklung-frage-antwort-db.com.de

Ruhezustand: LazyInitializationException: Proxy konnte nicht initialisiert werden

Hier ist eine, die mich verwirrt hat. Ich versuche, eine grundlegende Hibernate-DAO-Struktur zu implementieren, habe jedoch 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 beim dritten assertTrue fehl, bei dem versucht wird, 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)
70
Piko

Das Problem ist, dass Sie versuchen, auf eine Auflistung in einem Objekt zuzugreifen, das nicht verbunden ist. Sie müssen das Objekt erneut anhängen, bevor Sie auf die Sammlung für die aktuelle Sitzung zugreifen können. Sie können das durch machen

session.update(object);

Mit lazy=false ist keine gute Lösung, da Sie die Lazy Initialization-Funktion des Ruhezustands wegwerfen. Wann lazy=false wird die Sammlung zur gleichen Zeit in den Speicher geladen, zu der das Objekt angefordert wird. Dies bedeutet, dass wenn wir eine Sammlung mit 1000 Objekten haben, alle in den Speicher geladen werden, obwohl wir darauf zugreifen werden oder nicht. Und das ist nicht gut.

Bitte lesen Sie diesen Artikel wo er das Problem erklärt, die möglichen Lösungen und warum er auf diese Weise implementiert wird. Um Sitzungen und Transaktionen zu verstehen, müssen Sie auch diesen anderen Artikel lesen.

68
pakore

Dies bedeutet in der Regel, dass die Sitzung im Ruhezustand bereits geschlossen wurde. Sie können eine der folgenden Maßnahmen ergreifen, um das Problem zu beheben:

  1. verwenden Sie für jedes Objekt, das dieses Problem verursacht, HibernateTemplate.initialize(object name)
  2. Verwenden lazy=false in deinen hbm files.
14
digitalsanctum

Siehe meinen Artikel. Ich hatte das gleiche Problem - LazyInitializationException - und hier ist die Antwort, die ich endlich gefunden habe:
http://community.jboss.org/wiki/LazyInitializationExceptionovercome
Lazy = false zu setzen ist nicht die Antwort - es kann alles auf einmal laden, und das ist nicht unbedingt gut. Beispiel:
1 Datensatz Tabelle A Referenzen:
5 Datensätze Tabelle B Referenzen:
25 Datensätze Tabelle C Referenzen:
125 Datensätze Tabelle D
...
etc. Dies ist nur ein Beispiel dafür, was schief gehen kann.
- Tim Sabin

11
Tim Sabin

Wenn Sie den Ruhezustand mit JPA-Anmerkungen verwenden, ist dies hilfreich. In Ihrer Serviceklasse sollte es einen Setter für Entity Manager mit @PersistenceContext geben. Ändern Sie dies in @PersistenceContext (Typ = PersistenceContextType.EXTENDED). Dann können Sie faul Eigentum in jedem zugreifen, wo.

7
konda

wenn Sie Lazy Loading verwenden, muss Ihre Methode mit einem Kommentar versehen werden

@TransactionAttribute(TransactionAttributeType.REQUIRES_NEW) für zustandslose Sitzung EJB

4
Rolando Quezada

Wir sind auch auf diesen Fehler gestoßen. Um das Problem zu lösen, haben wir der Hibernate-Zuordnungsdatei ein lazy = false hinzugefügt.

Es scheint, dass wir eine Klasse A hatten, die sich in einer Sitzung befindet, die eine andere Klasse B lädt. Wir versuchen, auf die Daten der 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>  
3
chris

Wenn Sie über die Auswirkungen von lazy=false Bescheid wissen und es dennoch als Standard festlegen möchten (z. B. für Prototyping-Zwecke), können Sie eine der folgenden Optionen verwenden:

  • wenn Sie eine XML-Konfiguration verwenden: Fügen Sie default-lazy="false" zu Ihrem <hibernate-mapping> - Element hinzu
  • wenn Sie eine Anmerkungskonfiguration verwenden: Fügen Sie Ihrer Entitätsklasse (n) @Proxy(lazy=false) hinzu.
2
Shayanlinux

Es scheint, dass nur Ihr DAO eine Sitzung verwendet. Daher wird für jeden Aufruf einer DAO-Methode eine neue Sitzung geöffnet und dann geschlossen. Somit kann die Ausführung des Programms fortgesetzt werden als:

// 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 Erfassung und Zuordnung in einer Entität verzögert: Sie werden bei Bedarf aus der Datenbank geladen. Somit:

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

löst eine Ausnahme aus, weil ein neues Laden von der Datenbank angefordert wird und die Sitzung, die mit dem Laden der Entität verbunden ist, bereits geschlossen wurde.

Es gibt zwei Ansätze, um dieses Problem zu beheben:

  • erstellen Sie eine Sitzung, um all unseren Code einzuschließen. Dies würde bedeuten, dass Sie Ihren DAO-Inhalt ändern, um nicht eine zweite Sitzung zu eröffnen

  • erstellen Sie eine Sitzung, und aktualisieren Sie Ihre Entität (d. h. verbinden Sie sie erneut) mit dieser Sitzung, bevor Sie die Behauptungen aufstellen.

    session.update (Objekt);

2
Kartoch

Okay, endlich herausgefunden, wo ich nachlässig war. Ich hatte die falsche Vorstellung, dass ich jede DAO-Methode in eine Transaktion einschließen sollte. Schrecklich falsch! Ich habe meine Lektion gelernt. Ich habe den gesamten Transaktionscode aus allen DAO-Methoden geholt und Transaktionen ausschließlich auf Anwendungs-/Managerebene eingerichtet. Dies hat alle meine Probleme vollständig gelöst. Die Daten werden bei Bedarf ordnungsgemäß faul geladen, eingepackt und heruntergefahren, sobald ich das Commit ausgeführt habe.

Das Leben ist gut ... :)

2
Piko

verwenden Sie Hibernate.initialize für Lazy Field

1
myururdurmaz

Wenn Sie die Ruhezustandssitzung manuell verwalten, können Sie in sessionFactory.getCurrentSession () und den zugehörigen Dokumenten nachsehen:

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

1
cliff.meyers

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 class-Tag gibt es eine Eigenschaft namens lazy . Setzen Sie diese Eigenschaft auf true. Das folgende hbm-Beispiel zeigt eine Möglichkeit, die Lazy-Eigenschaft auf false festzulegen.

`id ... '

Wenn Sie stattdessen Anmerkungen verwenden, lesen Sie die Dokumentation zum Ruhezustand. http://docs.jboss.org/hibernate/stable/annotations/reference/en/html_single/

Ich hoffe das hat geholfen.

1

Wenn Sie Spring- und JPA-Annotation verwenden, können Sie Probleme mit der Sitzung bei der verzögerten Initialisierung am einfachsten vermeiden, indem Sie Folgendes wiederholen:

@PersistenceContext   

zu

@PersistenceContext(type = PersistenceContextType.EXTENDED)
1
DmRomantsov

Standardmäßig werden alle one-to-many - und many-to-many - Zuordnungen beim ersten Zugriff verzögert abgerufen.

In Ihrem Anwendungsfall können Sie dieses Problem beheben, indem Sie alle DAO-Vorgänge in eine logische Transaktion packen:

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, beim Laden Ihrer Entität alle LAZY-Zuordnungen abzurufen, sodass:

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

sollte auch den LAZY submissionType holen:

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

Auf diese Weise können Sie schnell alle faulen Eigenschaften abrufen und auch nach dem Schließen der Sitzung darauf zugreifen.

Sie können beliebig viele [one|many]-to-one - Zuordnungen und eine "[one | many] -to-many" -Listenzuordnung abrufen (da 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-Entität verwenden.

0
Vlad Mihalcea