Wie lösen die "konnte nicht träge initialize a collection of role" Hibernate exception
Habe ich dieses problem:
org.hibernate.LazyInitializationException: failed to faul initialize a collection of role: mvc3.Modell.Thema.Kommentare, keine Sitzung oder die Sitzung geschlossen wurde
Hier ist das Modell:
@Entity
@Table(name = "T_TOPIC")
public class Topic {
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private int id;
@ManyToOne
@JoinColumn(name="USER_ID")
private User author;
@Enumerated(EnumType.STRING)
private Tag topicTag;
private String name;
private String text;
@OneToMany(mappedBy = "topic", cascade = CascadeType.ALL)
private Collection<Comment> comments = new LinkedHashSet<Comment>();
...
public Collection<Comment> getComments() {
return comments;
}
}
Den controller, die fordert, das Modell sieht wie folgt aus:
@Controller
@RequestMapping(value = "/topic")
public class TopicController {
@Autowired
private TopicService service;
private static final Logger logger = LoggerFactory.getLogger(TopicController.class);
@RequestMapping(value = "/details/{topicId}", method = RequestMethod.GET)
public ModelAndView details(@PathVariable(value="topicId") int id)
{
Topic topicById = service.findTopicByID(id);
Collection<Comment> commentList = topicById.getComments();
Hashtable modelData = new Hashtable();
modelData.put("topic", topicById);
modelData.put("commentList", commentList);
return new ModelAndView("/topic/details", modelData);
}
}
Der jsp-Seite sieht li die folgenden:
<%@page import="com.epam.mvc3.helpers.Utils"%>
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ page session="false" %>
<html>
<head>
<title>View Topic</title>
</head>
<body>
<ul>
<c:forEach items="${commentList}" var="item">
<jsp:useBean id="item" type="mvc3.model.Comment"/>
<li>${item.getText()}</li>
</c:forEach>
</ul>
</body>
</html>
Ausnahme ist aufblühte, wenn anzeigen jsp. In der Zeile mit c:forEach Schleife
Du musst angemeldet sein, um einen Kommentar abzugeben.
Wenn Sie wissen, dass Sie wollen, um zu sehen, alle
Comment
s jedes mal, wenn Sie rufen Sie eineTopic
dann ändern Sie Ihre Feld-mapping fürcomments
zu:Sammlungen faul sind-standardmäßig geladen, werfen Sie einen Blick auf diese wenn Sie mehr wissen wollen.
Aus meiner Erfahrung, habe ich die folgenden Methoden gelöst, die berühmten LazyInitializationException:
(1) Verwenden Sie Den Ruhezustand.initialisieren
(2) Verwenden von JOIN-FETCH
Können Sie die Verwendung der JOIN-FETCH-syntax in der JPQL explizit Holen Sie das Kind-Kollektion heraus. Dies ist, wie einige, wie EIFRIG abrufen.
(3) Die Verwendung OpenSessionInViewFilter
LazyInitializationException oft kommt es in der view-Schicht. Wenn Sie das Spring-framework, die Sie verwenden können, OpenSessionInViewFilter. Allerdings glaube ich nicht empfehlen Ihnen, dies zu tun. Kann es führt zu performance-Problem, wenn nicht richtig verwenden.
Der Ursprung des Problems:
Standardmäßig hibernate träge zu Lasten der Sammlungen (Beziehungen), was bedeutet, whenver Sie verwenden die
collection
im code(hiercomments
Feldin
Topic
Klasse)das hibernate wird, dass aus der Datenbank, das problem ist jetzt, dass Sie immer die Kollektion im controller (wo die
JPA-Sitzung wird geschlossen).Dies ist die Zeile code, der die Ausnahme verursacht
(wo Sie laden die
comments
Sammlung):Du immer "Kommentare" - Kollektion (Thema.getComments()) im controller(wo
JPA session
geendet hat), und dass die Ausnahme verursacht. Auch wenn Sie hattendie
comments
Sammlung in Ihrer jsp-Datei wie folgt ein(anstatt es im controller):Würden Sie immer noch die gleichen Ausnahme für den gleichen Grund.
Die Lösung des Problems:
Da kann man einfach nur zwei Sammlungen mit der
FetchType.Eager
(eifrig holte-Sammlung) in einer Entity-Klasse und da lazy loading ist mehreffizienter als eifrig be -, ich denke, dass dieser Weg für die Lösung Ihres Problems ist besser, als nur die änderung der
FetchType
zu eifrig:Wenn Sie wollen, um die Sammlung lazy initialisiert, und auch diese Arbeit machen,
ist es besser, fügen Sie das code-snippet auf Ihrer
web.xml
:Was dieser code macht, ist, dass es erhöht die Länge der Ihre
JPA session
oder wie die Dokumentation sagt, es wird verwendet"to allow for lazy loading in web views despite the original transactions already being completed."
sodiese Art der JPA-Sitzung wird offen sein, ein wenig mehr, und weil der, dass
Sie können die träge Last Sammlungen in Ihrem jsp-Dateien und controller-Klassen.
Ich weiß, es ist eine alte Frage, aber ich möchte helfen.
Sie können die transactional annotation auf der service-Methode, die Sie brauchen, in diesem Fall findTopicByID(id) haben sollte
mehr info über diese Anmerkung gefunden werden kann hier
Über die anderen Lösungen:
ist nicht eine gute Praxis, es sollte NUR verwendet werden, wenn nötig.
Den hibernate-Initialisierer bindet Ihre Klassen, um die hibernate-Technologie. Wenn Sie darauf abzielen, flexibel zu sein, ist nicht ein guter Weg zu gehen.
Hoffe es hilft
@Transactional
eine Feder-nur was?Der Grund dafür ist, dass, wenn man lazy load, die Sitzung ist geschlossen.
Gibt es zwei Lösungen.
Nicht verwenden lazy load.
Set
lazy=false
im XML-oder im Set@OneToMany(fetch = FetchType.EAGER)
In annotation.Verwenden lazy load.
Set
lazy=true
im XML-oder im Set@OneToMany(fetch = FetchType.LAZY)
In annotation.und fügen Sie
OpenSessionInViewFilter filter
in Ihremweb.xml
Detail Siehe meine POST.
ich lösen dieses problem durch hinzufügen
@Transactional
ich denke, dadurch kann die session offenUm lazy load eine Sammlung es muss eine aktive Sitzung. In einer web-app gibt es zwei Möglichkeiten, dies zu tun. Sie können die Open Session In View Muster, wo Sie eine interceptor zu öffnen, die session am Anfang der Anfrage, und schließen Sie es am Ende. Das Risiko dort ist, dass Sie über solide exception-handling, oder Sie können binden Sie alle Ihre Sitzungen und Ihre app hängen könnte.
Den anderen Weg, dies zu behandeln ist, sammeln alle Daten, die Sie brauchen in Ihrer Steuerung, schließen Sie Ihre Sitzung, und dann Stopfen Sie die Daten in Ihr Modell. Ich persönlich bevorzuge diesen Ansatz, wie es scheint, ein wenig näher an den Geist des MVC-pattern. Auch wenn Sie eine Fehlermeldung erhalten, aus der Datenbank auf diese Weise, die Sie behandeln können es viel besser als wenn es passiert, in Ihrem view-renderer. Dein Freund in diesem Szenario ist Hibernate.initialisieren(myTopic.getComments()). Sie müssen auch bringen Sie das Objekt an die session, da bist du erstellen Sie eine neue Transaktion mit jeder Anforderung. Verwenden session.lock(myTopic,LockMode.NONE), dass für.
Das problem wird verursacht, durch den Zugriff auf ein Attribut mit der hibernate-session geschlossen. Sie haben nicht eine hibernate-Transaktion in den controller.
Mögliche Lösungen:
Alles tun, diese Logik, in der service-Schicht, (mit der @Transactional), nicht in den controller. Es sollte der richtige Ort sein, um dies zu tun, es ist Teil der Logik der app, nicht in den controller (in diesem Fall eine Schnittstelle, um das Modell zu laden). Alle Operationen in der service-Schicht sollten transaktional sein.
also: Verschieben Sie diese Zeile an die TopicService.findTopicByID Methode:
Sammlung commentList = topicById.getComments();
Verwenden 'begierig' anstelle von 'faul'. Jetzt sind Sie nicht mit "faul" .. es ist nicht wirklich eine Lösung, wenn Sie verwenden möchten, faul, funktioniert wie eine temporäre (sehr vorübergehende) Abhilfe.
Im Allgemeinen die beste Lösung ist die 1.
Wenn Sie versuchen, eine Beziehung zwischen einer Entität und einer Sammlung oder eine Liste von java-Objekten (zum Beispiel Lange Ausführung), er möchte so etwas wie dies:
Fand ich heraus, dass die Deklaration
@PersistenceContext
alsEXTENDED
löst auch dieses problem:Als ich erklärte, in dieser Artikel, der beste Weg, um behandeln Sie die
LazyInitializationException
ist, um es zu Holen, auf der Suche, wie diese:Sollten Sie IMMER vermeiden, die folgenden anti-Muster:
hibernate.enable_lazy_load_no_trans
- Hibernate-Konfiguration-EigenschaftStellen Sie daher sicher, dass Ihre
FetchType.LAZY
Verbände initialisiert werden zum Zeitpunkt der Abfrage oder im original@Transactional
Umfang mitHibernate.initialize
für sekundäre Sammlungen.TrassctionInterceptor
im stack-trace und das ist die.@Transactional-annotation-controller fehlt
Einer der besten Lösungen ist es, fügen Sie Folgendes in Ihre Anwendung.Eigenschaften Datei:
Frühjahr.jpa.Eigenschaften.hibernate.enable_lazy_load_no_trans=true
war es das problem, das ich vor kurzem konfrontiert, die ich gelöst mit der Verwendung von
detaillierte Beschreibung hier und das meinen Tag gerettet.
Ihre Liste ist lazy loading, so dass die Liste nicht geladen.
Anruf auf der Liste ist nicht genug.
Verwendung in Hibernate.initialisieren, um init der Liste.
Wenn dosnt Arbeit ausführen, die auf das element in der Liste und rufen Sie den Ruhezustand.initialisieren für jede .
diese werden müssen, bevor Sie wieder aus dem Transaktionsbereich.
Blick auf diese post.
Suche für
Lösen das problem in meinem Fall war es genau diese fehlende Zeile
in der Anwendung-Kontext-Datei.
Den
@Transactional
annotation über der Methode nicht berücksichtigt.Hoffe, die Antwort hilft jemand
Mithilfe der hibernate -
@Transactional
Anmerkung, wenn Sie ein Objekt aus der Datenbank mit lazy holte Attribute, Sie können einfach erhalten diese durch das Holen diese Attribute so :Hier in einer Hibernate-proxy-verwaltete Transaktion, die Tatsache der Berufung
ticket.getSales()
tun, anderen Abfrage zu Holen, Vertrieb, weil Sie explizit danach gefragt.Für diejenigen, die Arbeit mit Kriterien, fand ich, dass
Tat alles, was ich brauchte getan hatte.
Ersten fetch-Modus für Sammlungen festgelegt ist FetchMode.FAUL, um die Leistung, aber wenn ich die Daten benötigen, ich fügen Sie einfach diese Zeile und genießen Sie den voll besiedelten Objekte.
In meinem Fall folgenden code ein problem:
Weil es losgelöst von der Datenbank und Hibernate nicht mehr abgerufen Liste aus dem Feld, wenn es nötig war. So Initialisiere ich es vor dem ausbau:
Sammlung
comments
in Ihrer model-KlasseTopic
ist träge geladen, die ist der default-Verhalten, wenn Sie nicht beschriften Sie es mitfetch = FetchType.EAGER
speziell.Ist es überwiegend wahrscheinlich, dass Ihr
findTopicByID
service ist über eine stateless-Hibernate-session. Eine stateless session nicht über den first-level-cache, d.h., keine Persistenz-Kontext. Später, wenn Sie versuchen, zu Durchlaufencomments
, Hibernate, wird eine Ausnahme ausgelöst.Kann die Lösung sein:
Kommentieren
comments
mitfetch = FetchType.EAGER
Wenn Sie immer noch gerne Kommentare werden verzögert geladen, verwenden Sie Hibernate ist stateful sessions, so dass Sie in der Lage sein zu Holen Kommentare später auf Nachfrage.
Der Grund ist, Sie versuchen zu Holen Sie sich die commentList auf dem controller nach Schließung der Sitzung innerhalb des Dienstes.
Oben lädt die commentList nur, wenn Sie Ihre hibernate-session aktiv ist, ich denke mal, dass Sie geschlossen in Ihren Dienst.
Also, Sie haben, um die commentList vor Schließung der Sitzung.
Answer
In meiner cae, hatte ich das mapping b/w, A und B wie
Einen hat
in der DAO-Schicht, die Methode muss kommentiert werden mit
@Transactional
wenn Sie noch nicht kommentiert das mapping mit Fetch Art - GerneHallo Alle Beiträge ziemlich spät, hoffe es hilft anderen,
Dankend im Voraus @GMK für diesen Beitrag Hibernate.initialize(Objekt)
wenn Lazy="true"
nun, wenn ich auf " set " nach dem Abschluss-Sitzung, es wird eine Ausnahme ausgegeben.
Meine Lösung :
nun kann ich Zugriff auf 'set', auch nach schließen der Hibernate-Session.
Noch einen anderen Weg, um die Sache, die Sie verwenden können, TransactionTemplate wrap-around-the lazy Holen.
Wie
ich mit aufgelöst Liste anstelle von Set: