Ich verbessere eine alte Spring / Hibernate-Anwendung und bin festgefahren. Ich habe eine Methode, die eine Datei liest mehr als 3000 Zeilen lang, jede Zeile hat einen Datensatz, der mit etwas in der Datenbank verglichen werden muss und dann ein Register der Datenbank hinzugefügt werden muss (eine viele zu viele Tabelle).
>Tabellen und Relationen sind
Zweig haben viele Produkte , Produkte sind in vielen Branchen .
Produkte haben viele Produkte und eine Kategorie hat viele Produkte
Und es gibt mehr Tische, die dort waren und gut funktionieren.
Die neuen Tabellen / Objekte, die ich erstellt habe, sind Zweig, Produkt, BranchToProduct .
Produkte haben einen Satz von BranchToProduct -Objekten, die 3 Felder enthalten
Ich muss BranchToProduct-Objekte zu dem Produktsatz hinzufügen, wobei die drei Felder aus den Informationen gefüllt werden, die ich aus jeder Zeile der Datei erhalte.
Ich füge eine einfache Zeile und die Anwendung wirft:
Produkt = productDAO.findByModel (stringModel);
konnte nicht initialisiert werden a Sammlung von Rollen: com.bamboo.catW3.domain.Product.products, Keine Sitzung oder Sitzung wurde geschlossen
Wenn ich in das Hibernate-Mapping (hbm-Datei) gehe und die Beziehung product_to_products lazy = false anwähle, läuft die Zeile ganz gut, aber wenn ich versuche, sie in den Dateizyklus zu legen, bleibt die Anwendung immer an der 18. Zeile hängen Es ist egal, welche Datei ich verwende oder die Reihenfolge des Inhalts, die Konsole funktioniert nicht mehr, ich muss Java schließen, um den Prozess zu beenden.
Wie auch immer, beim Debuggen erhalte ich eine Menge HQLs für einen einfachen Fund, 13 Zeilen HQL, bis ich meinen Fehler bekomme, wenn faul = true, und eine Menge Zeilen, wenn ich faul = false benutze und auf die Zyklus.
Ich denke, ich sollte versuchen, das Problem mit faul = wahr zu lösen.
Diese Situation lässt mich fragen:
1.- Wenn faul = wahr. Wie kann ich eine einzelne Zeile dieses Befehls diese Methode ausführen, aber es funktioniert gut auf andere Methoden der Klasse?
Übrigens ist dies eine Klasse namens CatalogFacade, die Methoden anderer Klassen implementiert: (CategoryFacade, ContainerFacade, ProductFacade, ProductOptionFacade, ProductStatusFacade, UserFacade, EmailFacade, FileFacade, BranchOfficeFacade)
Dies ist der Code für das
productDao.find ():
Die Ausnahme wird direkt in diese Zeile geworfen, zuletzt für:
%Vor%Im Debugger von Intelij kann ich das Objekt sehen, das fälschlicherweise aus der Abfrage gebildet wurde:
product.getProducts () = {org.hibernate.collection.PersistentSet@4312}unfähig zum Auswerten des Ausdrucks Method hat 'org.hibernate.LazyInitializationException' Ausnahme ausgelöst.
Wie auch immer die anderen Attribute in Ordnung sind. Dieses Produkt hat nicht einmal andere Produkte in der Datenbank.
AKTUALISIEREN
DECKEN DEEPER auf die Situation, innerhalb der
product.find (int)
In der Zeile, bevor ich die Ausnahme erhalte, können wir in der Fehlersuche sehen, dass das product.products -Array einen Fehler hat, anstelle des Wertes, den Sie die lazyInitialitationException sehen können. Wie auch immer , wenn ich es von einer anderen Methode aus anrufe, wird das Array gefunden. Es kann also nicht drin sein Obwohl die Methode nur eine Ganzzahl erhält.
Außerdem haben wir festgestellt, dass dies während des gesamten Lebenszyklus der Anwendung passiert ist. Manchmal haben die Mitarbeiter eine Methode wie diese repliziert, änderten sie jedoch und setzten null auf diese beschädigten Arrays. Ich bin also 100% sicher, dass diese Anwendung mehr Ressourcen verbraucht, als sie sollte.
Es hat Ansichten in Flex, und spätere Ansichten in JSTL wurden erstellt, und abhängig davon, wer die Methoden aufruft, werden die Ausnahmen auf verschiedene Arten für dieselben Methoden ausgelöst.
Hinzufügen weiterer Informationen So ist produt.find im AbstractDAOImpl implementiert:
%Vor%und dies ist meine Transaction Manager-Konfiguration, die in der ersten Antwort von foipip beschriebene Annotationsmethode hat nicht funktioniert:
%Vor%
Sie erhalten eine träge Initialisierungsausnahme, weil Ihre Sitzung geschlossen wird, bevor Sie auf die Mitgliedsvariablen des Produkts zugreifen. Wenn die folgende Zeile ausgeführt wird:
%Vor%Hibernate öffnet eine Sitzung, ruft das Gesuchte ab und schließt dann die Sitzung. Alle Felder, die faul sind = wahr, werden zu diesem Zeitpunkt nicht abgerufen. stattdessen werden diese Felder durch Proxies ausgefüllt. Wenn Sie versuchen, den tatsächlichen Wert des proxied-Objekts abzurufen, versucht es, mit der aktiven Sitzung zurück zu der Datenbank zu gehen, um die Daten abzurufen. Wenn keine Sitzung gefunden werden kann, erhalten Sie die Ausnahme, die Sie sehen. Das Setzen von faul = wahr hat Vorteile, weil es verhindert, dass der gesamte Objektgraph sofort geladen wird; Verschachtelte Objekte werden in Ruhe gelassen, bis Sie gezielt nach ihnen fragen.
Es gibt zwei gebräuchliche Techniken, um mit Ihrem Problem umzugehen. Die erste, die Sie bereits identifiziert haben, ist die Einstellung faul = false. Dies ist in Ordnung, wenn ein Produkt immer über Produktattribute verfügt und Sie normalerweise ein Produkt und seine Attribute zusammen verwenden. Wenn Sie häufig nur das Product-Objekt ohne seine Attribute benötigen, erstellen Sie eine unnötige Datenbanklast.
Die zweite Technik besteht darin, eine Methode als Transaktion mit Spring-Annotationen zu markieren.
%Vor%Einige Anmerkungen:
Ich hatte das gleiche Problem zuvor und habe es mit verschiedenen Hibernate-Methoden behoben. Ich benutze
%Vor%um alles zu bekommen, und
%Vor%um eine einzige Sache zu finden. Beide benutze ich ohne Probleme. Ich fand, dass .find () gibt mir, dass die Sitzung wurde geschlossen Fehler.
Ich habe nicht wirklich darüber nachgedacht, warum das so ist.
Die einzige andere Option, die mir neben der Verwendung einer anderen Methode einfällt, ist das Öffnen und Schließen von Sitzungen selbst, aber ich nehme an, dass Sie das lieber nicht tun.
Ersetzen Sie die Lade-Methode durch die Methode get.
Ich habe nach mehr Nachforschungen herausgefunden, dass die Lade-Methode das Objekt nicht wirklich aus der Datenbank lädt. Stattdessen wird automatisch ein Proxy-Objekt zurückgegeben. Load setzt voraus, dass das Objekt bereits von der Datenbank "get get" bekommen hat und sich im Cache befindet.
Verwenden Sie einfach get anstelle von load, wenn Sie sicherstellen möchten, dass Sie die Datenbank gefunden haben, und stellen Sie sicher, dass Sie den Unterschied zwischen diesen beiden Methoden kennen.
Quelle: dies Frühling Forum Kommentar
Ich habe das persönlich getestet und es ist richtig, dass die Lade-Methode nicht alle gewünschten Daten aus der DB holt. Mit get mein Problem behoben.