Tengo este problema
org.hibernate.LazyInitializationException: no se pudo inicializar perezosamente una colección de roles: mvc3.model.Topic.comments, no se cerró ninguna sesión o 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 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 aumenta cuando se ve jsp. En la línea con c: forEach loop
Desde mi experiencia, tengo los siguientes métodos para resolver la famosa LazyInitializationException:
(1) Use Hibernate.initialize
(2) Utilice JOIN FETCH
Puede usar la sintaxis JOIN FETCH en su JPQL para recuperar explícitamente la colección secundaria. Esto es algo así como buscar EAGER.
(3) Use OpenSessionInViewFilter
LazyInitializationException a menudo ocurre en la capa de vista. Si usa Spring Framework, puede usar OpenSessionInViewFilter. Sin embargo, no te sugiero que lo hagas. Puede conducir a problemas de rendimiento si no se usa correctamente.
fuente
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
Puede encontrar más información sobre esta anotación aquí
Sobre las otras soluciones:
No es una buena práctica, debe usarse SOLO si es necesario.
El inicializador de hibernación une sus clases a la tecnología de hibernación. Si quiere ser flexible, no es un buen camino a seguir.
Espero eso ayude
fuente
@Transactional
una cosa solo de primavera?El origen de tu problema:
Por defecto, hibernate carga perezosamente las colecciones (relaciones), lo que significa que cada vez que usa el
collection
código (aquí elcomments
campo en laTopic
clase) el hibernate lo obtiene de la base de datos, ahora el problema es que está obteniendo la colección en su controlador (donde se encuentra la sesión JPA está cerrado). Esta es la línea de código que causa la excepción (donde está cargando lacomments
colección):Está recibiendo una colección de "comentarios" (topic.getComments ()) en su controlador (donde
JPA session
ha finalizado) y eso causa la excepción. Además, si obtuvo lacomments
colección en su archivo jsp de esta manera (en lugar de obtenerla en su controlador):Aún tendría la misma excepción por el mismo motivo.
Resolviendo el problema:
Debido a que solo puede tener dos colecciones con la
FetchType.Eager
(colección obtenida con entusiasmo) en una clase de entidad y debido a que la carga diferida es más eficiente que la cargaFetchType
ansiosa , creo que esta forma de resolver su problema es mejor que simplemente cambiar a ansioso:Si desea inicializar la colección perezosa y también hacer que esto funcione, es mejor agregar este fragmento de código a su
web.xml
:Lo que hace este código es que aumentará la longitud de su
JPA session
o, como dice la documentación, se usa, de"to allow for lazy loading in web views despite the original transactions already being completed."
esta manera la sesión JPA se abrirá un poco más y, por eso, puede cargar colecciones en sus archivos jsp y clases de controlador .fuente
La razón es que cuando usa la carga diferida, la sesión se cierra.
Hay dos soluciones
No use carga perezosa.
Establecer
lazy=false
en XML o establecer@OneToMany(fetch = FetchType.EAGER)
en anotación.Use carga perezosa.
Establecer
lazy=true
en XML o establecer@OneToMany(fetch = FetchType.LAZY)
en anotación.y agregue
OpenSessionInViewFilter filter
en suweb.xml
Detalle Ver mi POST .
fuente
resuelvo este problema agregando
@Transactional
, creo que esto puede abrir la sesiónfuente
El problema se debe al acceso a un atributo con la sesión de hibernación cerrada. No tiene una transacción de hibernación en el controlador.
Soluciones posibles:
Haga toda esta lógica, en la capa de servicio , (con @Transactional), no en el controlador. Debe haber el lugar correcto para hacer esto, es parte de la lógica de la aplicación, no en el controlador (en este caso, una interfaz para cargar el modelo). Todas las operaciones en la capa de servicio deben ser transaccionales. es decir: mueva esta línea al método TopicService.findTopicByID:
Colección commentList = topicById.getComments ();
Use 'ansioso' en lugar de 'perezoso' . Ahora no está usando 'perezoso' ... no es una solución real, si quiere usar perezoso, funciona como una solución temporal (muy temporal).
En general, la mejor solución es el 1.
fuente
Para cargar una colección de forma diferida, debe haber una sesión activa. En una aplicación web hay dos formas de hacer esto. Puede usar el patrón Abrir sesión en vista , donde usa un interceptor para abrir la sesión al comienzo de la solicitud y cerrarla al final. El riesgo es que debe tener un manejo sólido de excepciones o podría bloquear todas sus sesiones y su aplicación podría bloquearse.
La otra forma de manejar esto es recopilar todos los datos que necesita en su controlador, cerrar su sesión y luego ingresar los datos en su modelo. Personalmente prefiero este enfoque, ya que parece un poco más cercano al espíritu del patrón MVC. Además, si obtiene un error de la base de datos de esta manera, puede manejarlo mucho mejor que si ocurre en su renderizador de vistas. Su amigo en este escenario es Hibernate.initialize (myTopic.getComments ()). También deberá volver a adjuntar el objeto a la sesión, ya que está creando una nueva transacción con cada solicitud. Use session.lock (myTopic, LockMode.NONE) para eso.
fuente
Como expliqué en este artículo , la mejor manera de manejarlo
LazyInitializationException
es buscarlo al momento de la consulta, así:SIEMPRE debe evitar los siguientes antipatrones:
hibernate.enable_lazy_load_no_trans
propiedad de configuración de HibernatePor lo tanto, asegúrese de que sus
FetchType.LAZY
asociaciones se inicialicen en el momento de la consulta o dentro del@Transactional
alcance original utilizandoHibernate.initialize
colecciones secundarias.fuente
TrassctionInterceptor
seguimiento en la pila y ese es el indicado.Si está intentando tener una relación entre una entidad y una Colección o una Lista de objetos java (por ejemplo, Tipo largo), le gustaría algo como esto:
fuente
Una de las mejores soluciones es agregar lo siguiente en su archivo application.properties: spring.jpa.properties.hibernate.enable_lazy_load_no_trans = true
fuente
Descubrí que declarar
@PersistenceContext
comoEXTENDED
también resuelve este problema:fuente
fue el problema que enfrenté recientemente que resolví con el uso
Descripción más detallada aquí y esto me salvó el día.
fuente
su lista se está cargando lentamente, por lo que la lista no se cargó. Llamar para entrar en la lista no es suficiente. use en Hibernate.initialize para iniciar la lista. Si el trabajo de dosificación se ejecuta en el elemento de la lista y llame a Hibernate.initialize para cada uno. Esto debe ser antes de regresar del alcance de la transacción. mira esta publicación
buscar -
fuente
Para resolver el problema en mi caso, solo faltaba esta línea
en el archivo de contexto de la aplicación.
La
@Transactional
anotación sobre un método no se tuvo en cuenta.Espero que la respuesta ayude a alguien
fuente
@ Falta la anotación transaccional en el controlador
fuente
Al usar la
@Transactional
anotación de hibernación , si obtiene un objeto de la base de datos con atributos recuperados de manera diferida, simplemente puede obtenerlos recuperando estos atributos de esta manera:Aquí, en una transacción administrada por proxy de Hibernate, el hecho de llamar
ticket.getSales()
hace otra consulta para obtener ventas porque lo solicitó explícitamente.fuente
Dos cosas que deberías tener
fetch = FetchType.LAZY
.y
fuente
Para aquellos que trabajan con Criteria , encontré que
Hice todo lo que necesitaba.
El modo de recuperación inicial para colecciones se establece en FetchMode.LAZY para proporcionar rendimiento, pero cuando necesito los datos, solo agrego esa línea y disfruto de los objetos completamente poblados.
fuente
En mi caso, el siguiente código fue un problema:
Porque se separó de la base de datos e Hibernate ya no recuperó la lista del campo cuando era necesario. Entonces lo inicializo antes de separar:
fuente
La razón es que está tratando de obtener la lista de comentarios en su controlador después de cerrar la sesión dentro del servicio.
Arriba cargará la lista de comentarios solo si su sesión de hibernación está activa, lo que supongo que cerró en su servicio.
Por lo tanto, debe obtener la Lista de comentarios antes de cerrar la sesión.
fuente
Answer
La colección
comments
en su clase de modeloTopic
se carga lentamente, que es el comportamiento predeterminado si no lo anotafetch = FetchType.EAGER
específicamente.Es muy probable que su
findTopicByID
servicio esté utilizando una sesión de Hibernate sin estado. Una sesión sin estado no tiene el caché de primer nivel, es decir, no tiene contexto de persistencia. Más adelante, cuando intente iterarcomments
, Hibernate lanzará una excepción.La solución puede ser:
Anotar
comments
confetch = FetchType.EAGER
Si aún desea que los comentarios se carguen de manera diferida, use las sesiones con estado de Hibernate , para que pueda obtener comentarios más tarde a pedido.
fuente
En mi caso, tenía el mapeo b / w
A
y meB
gustaA
tieneen la
DAO
capa, el método debe ser anotado@Transactional
si no ha anotado la asignación con Fetch Type - Eagerfuente
No es la mejor solución, pero para aquellos que se enfrentan
LazyInitializationException
especialmente enSerialization
esto será de ayuda. Aquí verificará las propiedades y la configuración inicializadas de manera perezosanull
. Para eso crea la clase de abajoDentro de su clase de entidad que tiene propiedades inicializadas perezosamente agregue un método como se muestra a continuación. Agregue todas sus propiedades de carga perezosa dentro de este método.
Llame a este
checkLazyIntialzation()
método después en todos los lugares donde está cargando datos.fuente
Hola a todos, publicando bastante tarde, espero que ayude a otros, agradeciendo de antemano a @GMK por esta publicación Hibernate.initialize (objeto)
cuando perezoso = "verdadero"
ahora si accedo a 'set' después de cerrar la sesión, arroja una excepción.
Mi solución :
ahora puedo acceder a 'set' incluso después de cerrar Hibernate Session.
fuente
Otra forma de hacer la cosa, puede usar TransactionTemplate para envolver la recuperación perezosa. Me gusta
fuente
El problema se debe a que el código está accediendo a una relación JPA perezosa cuando la "conexión" a la base de datos está cerrada ( el contexto de persistencia es el nombre correcto en términos de Hibernate / JPA).
Una manera simple de resolverlo en Spring Boot es definiendo una capa de servicio y usando la
@Transactional
anotación. Esta anotación en un método crea una transacción que se propaga a la capa del repositorio y mantiene abierto el contexto de persistencia hasta que finaliza el método. Si accede a la colección dentro del método transaccional, Hibernate / JPA obtendrá los datos de la base de datos.En su caso, solo necesita anotar con
@Transactional
el métodofindTopicByID(id)
en suTopicService
y forzar la búsqueda de la colección en ese método (por ejemplo, preguntando su tamaño):fuente
Para deshacerse de la excepción de inicialización diferida, no debe solicitar la recopilación diferida cuando opera con objetos separados.
Desde mi opinión, el mejor enfoque es usar DTO, y no una entidad. En este caso, puede establecer explícitamente los campos que desea utilizar. Como siempre es suficiente. No hay que preocuparse de que algo como Jackson
ObjectMapper
, ohashCode
generado por Lombok llame a sus métodos implícitamente.Para algunos casos específicos, puede usar la
@EntityGrpaph
anotación, que le permite realizar laeager
carga incluso si tienefetchType=lazy
en su entidad.fuente
Hay varias soluciones para este problema de inicialización diferida:
1) Cambie el tipo de Fetch de asociación de LAZY a EAGER, pero esto no es una buena práctica porque esto degradará el rendimiento.
2) Use FetchType.LAZY en el objeto asociado y también use la anotación transaccional en su método de capa de servicio para que la sesión permanezca abierta y cuando llame a topicById.getComments (), se cargará el objeto secundario (comentarios).
3) Además, intente utilizar el objeto DTO en lugar de la entidad en la capa del controlador. En su caso, la sesión se cierra en la capa del controlador. MUCHO mejor para convertir la entidad a DTO en la capa de servicio.
fuente
Resolví usar List en lugar de Set:
fuente