Cómo resolver la excepción de Hibernación "no se pudo inicializar de forma diferida una colección de funciones"

Resuelto Eugene asked hace 12 años • 34 respuestas

Esta es la excepción:

org.hibernate.LazyInitializationException: no se pudo inicializar de forma diferida una colección de roles: mvc3.model.Topic.comments, no se cerró ninguna sesión o se cerró la sesión

Aquí está el modelo:

@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;
    }

}

El controlador, que llama al modelo, tiene el siguiente aspecto:

@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);       
     }
}

La página jsp tiene el siguiente aspecto:

<%@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>

La excepción se produce al visualizar el archivo jsp. En la línea con c:forEach bucle

Eugene avatar Aug 01 '12 01:08 Eugene
Aceptado

Si sabe que querrá ver todos Commentlos correos electrónicos cada vez que recupere un Topic, cambie su asignación de campos commentsa:

@OneToMany(fetch = FetchType.EAGER, mappedBy = "topic", cascade = CascadeType.ALL)
private Collection<Comment> comments = new LinkedHashSet<Comment>();

Las colecciones se cargan de forma diferida de forma predeterminada; eche un vistazo a esto si desea saber más.

darrengorman avatar Jul 31 '2012 18:07 darrengorman

Desde mi experiencia, tengo los siguientes métodos para resolver los famosos LazyInitializationException:

(1) Utilice Hibernate.initialize

Hibernate.initialize(topics.getComments());

(2) Utilice UNIRSE Y BUSCAR

Puede utilizar la JOIN FETCHsintaxis de su JPQL para recuperar explícitamente la colección secundaria. Esto es de alguna manera como EAGERbuscar.

(3) Utilice OpenSessionInViewFilter

LazyInitializationExceptionA menudo ocurre en la capa de vista. Si usa Spring Framework, puede usar OpenSessionInViewFilter. Sin embargo, no te sugiero que lo hagas. Puede provocar problemas de rendimiento si no se utiliza correctamente.

Boris avatar Aug 01 '2012 07:08 Boris

Sé que es una vieja pregunta pero quiero ayudar. Puede poner la anotación transaccional en el método de servicio que necesita; en este caso, findTopicByID(id) debería tener

@Transactional(propagation=Propagation.REQUIRED, readOnly=true, noRollbackFor=Exception.class)

Puede encontrar más información sobre esta anotación aquí.

Acerca de las otras soluciones:

fetch = FetchType.EAGER 

No es una buena práctica, debe usarse SÓLO si es necesario.

Hibernate.initialize(topics.getComments());

El inicializador de hibernación vincula sus clases a la tecnología de hibernación. Si su objetivo es ser flexible, no es un buen camino a seguir.

Espero eso ayude

sarbuLopex avatar Jun 06 '2016 13:06 sarbuLopex

El origen de su problema:

De forma predeterminada, hibernar carga perezosamente las colecciones (relaciones), lo que significa que cada vez que usas el collectionen tu código (aquí commentsel campo en Topicclase), la hibernación lo obtiene de la base de datos, ahora el problema es que estás obteniendo la colección en tu controlador (donde está la sesión JPA). está cerrado). Esta es la línea de código que causa la excepción (donde está cargando la commentscolección):

    Collection<Comment> commentList = topicById.getComments();

Obtiene una colección de "comentarios" (topic.getComments()) en su controlador (donde JPA sessionterminó) y eso provoca la excepción. Además, si tuvieras la commentscolección en tu archivo jsp de esta manera (en lugar de tenerla en tu controlador):

<c:forEach items="topic.comments" var="item">
//some code
</c:forEach>

Seguirías teniendo la misma excepción por el mismo motivo.

Resolviendo el problema:

Debido a que solo puede tener dos colecciones con FetchType.Eager(colección recuperada con entusiasmo) en una clase de Entidad y debido a que la carga diferida es más eficiente que la carga con entusiasmo, creo que esta forma de resolver su problema es mejor que simplemente cambiar a FetchTypeansioso:

Si desea inicializar la colección de forma diferida y también hacer que esto funcione, es mejor agregar este fragmento de código a su web.xml:

<filter>
    <filter-name>SpringOpenEntityManagerInViewFilter</filter-name>
    <filter-class>org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>SpringOpenEntityManagerInViewFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

Lo que hace este código es que aumentará la longitud de su JPA sessiono, como dice la documentación, se usa "to allow for lazy loading in web views despite the original transactions already being completed."de esta manera la sesión JPA estará abierta un poco más y debido a eso puede cargar colecciones de manera diferida en sus archivos jsp y clases de controlador. .

Gandalf avatar Jul 17 '2015 18:07 Gandalf