Cómo resolver la excepción de hibernación "no se pudo inicializar perezosamente una colección de roles"


Tengo este problema:

Org.hibernación.LazyInitializationException: no se pudo inicializar perezosamente una colección de role: mvc3.modelo.Tema.comments, no session or session was closed

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 eleva al ver jsp. En la línea con c:forEach loop

Author: Vlad Mihalcea, 2012-07-31

26 answers

Si sabe que querrá ver todos los Comments cada vez que recupere un Topic, cambie su asignación de campos para comments a:

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

Las colecciones son cargadas perezosamente por defecto, echa un vistazo a esto si quieres saber más.

 155
Author: darrengorman,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:34:57

Desde mi experiencia, tengo los siguientes métodos para resolver la famosa excepción LazyInitializationException:

(1) Usa Hibernar.inicializar

Hibernate.initialize(topics.getComments());

(2) Use JOIN FETCH

Puede usar la sintaxis JOIN FETCH en su JPQL para obtener explícitamente la colección hija. Esto es como ir a buscar ANSIOSOS.

(3) Usar OpenSessionInViewFilter

LazyInitializationException a menudo ocurren en la capa de vista. Si utiliza Spring framework, usted puede usar OpenSessionInViewFilter. Sin embargo, no le sugiero que lo haga. Puede conduce a problemas de rendimiento si no se utiliza correctamente.

 136
Author: Boris,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-15 11:08:58

El origen de su problema:

De forma predeterminada, hibernate carga perezosamente las colecciones (relaciones), lo que significa que cuando use el collection en su código (aquí comments campo en la clase Topic ) el hibernate obtiene eso de la base de datos, ahora el problema es que está obteniendo la colección en su controlador (donde JPA session is closed).Esta es la línea de código que causa la excepción (donde está cargando la colección comments):

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

Usted está recibiendo "comentarios" colección (tema.getComments()) en su controlador (donde JPA session ha terminado) y eso causa la excepción. También si usted había conseguido la colección comments en su archivo jsp como esta (en lugar de obtenerla en su controlador):

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

Seguirías teniendo la misma excepción por la misma razón.

Resolviendo el problema:

Porque solo puede tener dos colecciones con la FetchType.Eager(colección buscada ansiosamente) en una clase de Entidad y porque la carga lenta es más eficiente que cargar ansiosamente, creo que esta forma de resolver su problema es mejor que simplemente cambiar el FetchType a ansioso:

Si desea tener la colección lazy inicializada, 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 session o como dice la documentación, se usa "to allow for lazy loading in web views despite the original transactions already being completed." para de esta manera la sesión de JPA estará abierta un poco más y por eso puedes cargar perezosamente colecciones en sus archivos jsp y clases de controlador.

 45
Author: gandalf,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-07-18 10:21:22

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) debe tener

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

Se 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, solo debe utilizarse si es necesario.

Hibernate.initialize(topics.getComments());

El inicializador de hibernación vincula sus clases a la tecnología de hibernación. Si usted está apuntando a ser flexible no es una buena manera de ir.

Espero que ayude

 34
Author: sarbuLopex,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:10:54

La razón es que cuando se utiliza carga perezosa, la sesión se cierra.

Hay dos soluciones.

  1. No utilice carga perezosa.

    Establece lazy=false en XML o Establece @OneToMany(fetch = FetchType.EAGER) en anotación.

  2. Use carga perezosa.

    Establecer lazy=true en XML o Establecer @OneToMany(fetch = FetchType.LAZY) en anotación.

    Y añadir {[4] } en su web.xml

Detalle Ver mi POST.

 28
Author: saneryee,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-10-24 11:09:37

Para cargar perezosamente una colección debe haber una sesión activa. En una aplicación web hay dos maneras de hacer esto. Puede usar el patrón Open Session In View, donde usa un interceptor para abrir la sesión al principio de la solicitud y cerrarla al final. El riesgo es que tenga un manejo sólido de excepciones o podría enlazar todas sus sesiones y su aplicación podría colgarse.

La otra forma de manejar esto es recopilar todos los datos que necesita en su controlador, cierre su sesión y luego rellene 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 sucede en su renderizador de vista. Su amigo en este escenario es Hibernar.inicializar(mitópico.getComments ()). También tendrá que volver a unir el objeto a la sesión, ya que está creando una nueva transacción con cada petición. Usar sesión.lock (myTopic, LockMode.NINGUNO) por eso.

 19
Author: GMK,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-08-02 17:47:20

El problema es causado por acceder a un atributo con la sesión de hibernación cerrada. No tiene una transacción de hibernación en el controlador.

Posibles soluciones:

  1. 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 transaccional. es decir: Mueve esta línea al TopicService.Método findTopicByID:

    Lista de comentarios de la colección = topicById.getComments ();

  2. Usa 'eager'en lugar de 'lazy' . Ahora no estás usando 'perezoso'.. no es una solución real, si desea utilizar perezoso, funciona como una solución temporal (muy temporal).

  3. utilice @Transactional en el Controlador. No se debe usar aquí, está mezclando la capa de servicio con la presentación, no es una buena diseño.
  4. use OpenSessionInViewFilter, muchas desventajas reportadas, posible inestabilidad.

En general, la mejor solución es el 1.

 14
Author: abentan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-02-13 14:17:16
@Controller
@RequestMapping(value = "/topic")
@Transactional

Resuelvo este problema agregando @Transactional, creo que esto puede hacer que la sesión se abra

 13
Author: RuiZhi Wang,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-04-10 16:36:50

Si está tratando de 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:

@ElementCollection(fetch = FetchType.EAGER)
    public List<Long> ids;
 10
Author: javaboygo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-08-24 14:50:11

Descubrí que declarar @PersistenceContext como {[2] } también resuelve este problema:

@PersistenceContext(type = PersistenceContextType.EXTENDED)
 9
Author: Elcin ABD,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-09-16 13:22:12

Falta @ Anotación transaccional en el controlador

@Controller
@RequestMapping("/")
@Transactional
public class UserController {
}
 6
Author: Xcoder,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-03-26 10:30:47

Fue el problema al que me enfrenté recientemente el que resolví usando

<f:attribute name="collectionType" value="java.util.ArrayList" />

Descripción más detallada aquí y esto me salvó el día.

 5
Author: tolgayilmaz,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-11-07 15:22:57

Su lista es de carga lenta, por lo que la lista no se cargó. llamar para entrar en la lista no es suficiente. uso en Hibernación.inicializar para iniciar la lista. Si el trabajo dosnt se ejecuta en el elemento list y llama a Hibernate.inicializar para cada uno . esto debe ser antes de regresar del alcance de la transacción. mira este post.
buscar -

Node n = // .. get the node
Hibernate.initialize(n); // initializes 'parent' similar to getParent.
Hibernate.initialize(n.getChildren()); // pass the lazy collection into the session 
 5
Author: Avihai Marchiano,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-10-24 11:24:30

Para resolver el problema en mi caso, solo faltaba esta línea

<tx:annotation-driven transaction-manager="myTxManager" />

En el archivo application-context.

La anotación @Transactional sobre un método no se tuvo en cuenta.

Espero que la respuesta ayude a alguien

 4
Author: Mario Biasi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-02-05 16:38:38

Para aquellos que trabajan con Criterios , encontré que

criteria.setFetchMode("lazily_fetched_member", FetchMode.EAGER);

Hice todo lo que necesitaba había hecho.

El modo de recuperación inicial para colecciones se establece en FetchMode.PEREZOSO para proporcionar rendimiento, pero cuando necesito los datos, simplemente añado esa línea y disfruto de los objetos completamente poblados.

 2
Author: velis,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-12-01 05:22:43

En mi caso el siguiente código fue un problema:

entityManager.detach(topicById);
topicById.getComments() // exception thrown

Debido a que se separó de la base de datos e Hibernar ya no se recuperaba la lista del campo cuando era necesario. Así que lo inicializo antes de separarlo:

Hibernate.initialize(topicById.getComments());
entityManager.detach(topicById);
topicById.getComments() // works like a charm
 2
Author: kiedysktos,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-02-03 09:36:53

Como expliqué en este artículo , la mejor manera de manejar el LazyInitializationException es recuperarlo en el momento de la consulta, así:

select t
from Topic t
left join fetch t.comments

Siempre debe evitar los siguientes anti-patrones:

Por lo tanto, asegúrese de que sus FetchType.LAZY asociaciones se inicializan en el momento de la consulta o dentro el ámbito original @Transactional usando Hibernate.initialize para colecciones secundarias.

 2
Author: Vlad Mihalcea,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-06-27 06:21:50

Usando la anotación hibernate @Transactional, si obtiene un objeto de la base de datos con atributos obtenidos perezosamente, simplemente puede obtenerlos obteniendo estos atributos de la siguiente manera:

@Transactional
public void checkTicketSalePresence(UUID ticketUuid, UUID saleUuid) {
        Optional<Ticket> savedTicketOpt = ticketRepository.findById(ticketUuid);
        savedTicketOpt.ifPresent(ticket -> {
            Optional<Sale> saleOpt = ticket.getSales().stream().filter(sale -> sale.getUuid() == saleUuid).findFirst();
            assertThat(saleOpt).isPresent();
        });
}

Aquí, en una transacción administrada por proxy de Hibernación, el hecho de llamar a ticket.getSales() hacer otra consulta para obtener ventas porque se lo pidió explícitamente.

 2
Author: Alex,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-07-25 11:59:54

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.

topicById.getComments();

Arriba cargará la lista de comentarios solo si su sesión de hibernación está activa, que supongo que cerró en su servicio.

Por lo tanto, tienes que obtener la lista de comentarios antes de cerrar la sesión.

 0
Author: aditya lath,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-03-16 10:11:10

En mi cae, tenía el mapeo b / w A y B como

A tiene

@OneToMany(mappedBy = "a", cascade = CascadeType.ALL)
Set<B> bs;

En la capa DAO, el método debe estar anotado con @Transactional si no ha anotado la asignación con Fetch Type-Eager

 0
Author: Shirgill Farhan Ansari,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-05-23 10:12:58

La colección comments en su clase de modelo Topic está cargada perezosamente, que es el comportamiento predeterminado si no la anota con fetch = FetchType.EAGER específicamente.

Es muy probable que su servicio findTopicByID esté usando una sesión de Hibernación sin estado. Una sesión sin estado no tiene la caché de primer nivel, es decir, sin contexto de persistencia. Más adelante, cuando intente iterar comments, Hibernar lanzará una excepción.

org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: mvc3.model.Topic.comments, no session or session was closed

La solución puede ser:

  1. Anotar comments con fetch = FetchType.EAGER

    @OneToMany(fetch = FetchType.EAGER, mappedBy = "topic", cascade = CascadeType.ALL)   
    private Collection<Comment> comments = new LinkedHashSet<Comment>();
    
  2. Si todavía desea que los comentarios se carguen perezosamente, use Las sesiones con estado de Hibernate, para que pueda obtener comentarios más adelante a pedido.

 0
Author: Yuci,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-07-20 10:32:18

Hola A todos publicando bastante tarde espero que ayude a los demás, Agradeciendo de antemano a @ GMK por este post Hibernar.inicializar(objeto)

Cuando perezoso = "verdadero"

Set<myObject> set=null;
hibernateSession.open
set=hibernateSession.getMyObjects();
hibernateSession.close();

Ahora, si tengo acceso a 'set' después de cerrar la sesión, arroja una excepción.

Mi solución:

Set<myObject> set=new HashSet<myObject>();
hibernateSession.open
set.addAll(hibernateSession.getMyObjects());
hibernateSession.close();

Ahora puedo acceder a 'set' incluso después de cerrar la sesión de Hibernación.

 0
Author: vic,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-07-25 06:41:48

Una de las mejores soluciones es agregar lo siguiente en su aplicación.archivo de propiedades: primavera.jpa.propiedad.hibernación.enable_lazy_load_no_trans = true

 0
Author: sreekmatta,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-08-01 23:24:38

Otra forma de hacerlo, puede usar TransactionTemplate para envolver la búsqueda perezosa. Como

Collection<Comment> commentList = this.transactionTemplate.execute
(status -> topicById.getComments());
 0
Author: aristotll,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-09-01 17:43:50

Añade esto a tu persistencia.xml

<property name="hibernate.enable_lazy_load_no_trans" value="true" />
 -1
Author: Mohammad-Hossein Jamali,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-04-10 20:03:27

Resolví usando List en lugar de Set:

private List<Categories> children = new ArrayList<Categories>();
 -8
Author: SaganTheBest,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-07-08 08:42:06