Eu tenho esse problema:
org.hibernate.LazyInitializationException: falha ao inicializar preguiçosamente uma coleção de funções: mvc3.model.Topic.comments, nenhuma sessão ou sessão foi fechada
Aqui está o 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;
}
}
O controlador, que chama modelo, se parece com o seguinte:
@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);
}
}
A página jsp parece com o seguinte:
<%@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>
A exceção é aumentada ao visualizar jsp. Na linha com loop c: forEach
Da minha experiência, tenho os seguintes métodos para resolver a famosa LazyInitializationException:
(1) Use Hibernate.initialize
(2) Use JOIN FETCH
Você pode usar a sintaxe JOIN FETCH no seu JPQL para buscar explicitamente a coleção filho. É assim que o EAGER busca.
(3) Use OpenSessionInViewFilter
LazyInitializationException geralmente ocorre na camada de exibição. Se você usa a estrutura Spring, pode usar o OpenSessionInViewFilter. No entanto, eu não sugiro que você faça isso. Isso pode levar a um problema de desempenho se não for usado corretamente.
fonte
Sei que é uma pergunta antiga, mas quero ajudar. Você pode colocar a anotação transacional no método de serviço necessário, neste caso, findTopicByID (id) deve ter
mais informações sobre esta anotação podem ser encontradas aqui
Sobre as outras soluções:
não é uma boa prática, deve ser usada SOMENTE se necessário.
O inicializador de hibernação vincula suas classes à tecnologia de hibernação. Se você pretende ser flexível, não é um bom caminho a percorrer.
Espero que ajude
fonte
@Transactional
uma coisa apenas de primavera?A origem do seu problema:
Por padrão, o hibernate carrega preguiçosamente as coleções (relacionamentos), o que significa que, sempre que você usa
collection
no seu código (comments
campo aqui naTopic
classe), o hibernate obtém isso do banco de dados, agora o problema é que você está obtendo a coleção no seu controlador (onde a sessão JPA esta é a linha de código que causa a exceção (onde você está carregando acomments
coleção):Você está recebendo a coleção de "comentários" (topic.getComments ()) em seu controlador (onde
JPA session
terminou) e isso causa a exceção. Além disso, se você obteve acomments
coleção no seu arquivo jsp assim (em vez de obtê-la no seu controlador):Você ainda teria a mesma exceção pelo mesmo motivo.
Resolvendo o problema:
Como você só pode ter apenas duas coleções com a
FetchType.Eager
(coleção buscada ansiosamente) em uma classe Entity e porque o carregamento lento é mais eficiente do que o carregamento ansioso, acho que essa maneira de resolver seu problema é melhor do que apenas mudarFetchType
para ansioso:Se você deseja que a coleção preguiçosa seja inicializada e também faça com que isso funcione, é melhor adicionar este trecho de código ao seu
web.xml
:O que esse código faz é que aumentará o tamanho do seu
JPA session
ou, conforme a documentação diz, é usado"to allow for lazy loading in web views despite the original transactions already being completed."
para que a sessão JPA seja aberta um pouco mais e, por isso, você pode carregar preguiçosamente coleções nos arquivos jsp e nas classes do controlador .fonte
O motivo é que, quando você usa carga lenta, a sessão é fechada.
Existem duas soluções.
Não use carga lenta.
Defina
lazy=false
na@OneToMany(fetch = FetchType.EAGER)
anotação XML ou Set In.Use carga lenta.
Defina
lazy=true
na@OneToMany(fetch = FetchType.LAZY)
anotação XML ou Set In.e adicione
OpenSessionInViewFilter filter
seuweb.xml
Detalhe Veja meu POST .
fonte
eu resolvo esse problema adicionando
@Transactional
, acho que isso pode abrir a sessãofonte
O problema é causado pelo acesso a um atributo com a sessão de hibernação fechada. Você não possui uma transação de hibernação no controlador.
Soluções possíveis:
Faça toda essa lógica, na camada de serviço (com o @Transactional), não no controlador. Deve haver o lugar certo para fazer isso, isso faz parte da lógica do aplicativo, não no controlador (neste caso, uma interface para carregar o modelo). Todas as operações na camada de serviço devem ser transacionais. Por exemplo: Mova esta linha para o método TopicService.findTopicByID:
Coleção commentList = topicById.getComments ();
Use 'ansioso' em vez de 'preguiçoso' . Agora você não está usando 'preguiçoso'. Não é uma solução real, se você deseja usá-lo, funciona como uma solução temporária (muito temporária).
Em geral, a melhor solução é a 1.
fonte
Para carregar lentamente uma coleção, deve haver uma sessão ativa. Em um aplicativo Web, há duas maneiras de fazer isso. Você pode usar o padrão Open Session In View , em que você usa um interceptador para abrir a sessão no início da solicitação e fechá-la no final. O risco é que você precise ter um tratamento sólido de exceções ou poderá vincular todas as suas sessões e o aplicativo poderá travar.
A outra maneira de lidar com isso é coletar todos os dados necessários em seu controlador, fechar sua sessão e inserir os dados em seu modelo. Pessoalmente, prefiro essa abordagem, pois parece um pouco mais próxima do espírito do padrão MVC. Além disso, se você receber um erro do banco de dados dessa maneira, poderá lidar com isso muito melhor do que se ocorrer no seu renderizador de exibição. Seu amigo nesse cenário é Hibernate.initialize (myTopic.getComments ()). Você também precisará anexar novamente o objeto à sessão, pois está criando uma nova transação com cada solicitação. Use session.lock (myTopic, LockMode.NONE) para isso.
fonte
Como expliquei neste artigo , a melhor maneira de lidar
LazyInitializationException
com isso é buscá-lo no momento da consulta, assim:Você deve sempre evitar os seguintes antipadrões:
hibernate.enable_lazy_load_no_trans
propriedade de configuração do HibernatePortanto, verifique se suas
FetchType.LAZY
associações foram inicializadas no momento da consulta ou dentro do@Transactional
escopo original, usandoHibernate.initialize
para coleções secundárias.fonte
TrassctionInterceptor
rastreamento na pilha e é esse.Se você está tentando ter uma relação entre uma entidade e uma coleção ou uma lista de objetos java (por exemplo, tipo Long), seria algo como isto:
fonte
Uma das melhores soluções é incluir o seguinte no arquivo application.properties: spring.jpa.properties.hibernate.enable_lazy_load_no_trans = true
fonte
Eu descobri que declarar
@PersistenceContext
comoEXTENDED
também resolve esse problema:fonte
foi o problema que enfrentei recentemente e resolvi usando
descrição mais detalhada aqui e isso salvou meu dia.
fonte
sua lista tem carregamento lento, por isso não foi carregada. ligar para entrar na lista não é suficiente. use no Hibernate.initialize para iniciar a lista. Se não funcionar, execute o elemento list e chame Hibernate.initialize para cada um. isso precisa ser feito antes que você retorne do escopo da transação. olhe para este post.
procurar por -
fonte
Para resolver o problema no meu caso, estava faltando esta linha
no arquivo de contexto do aplicativo.
A
@Transactional
anotação sobre um método não foi levada em consideração.Espero que a resposta ajude alguém
fonte
A anotação @Transactional no controlador está ausente
fonte
Usando a
@Transactional
anotação de hibernação , se você obtiver um objeto do banco de dados com atributos buscados preguiçosamente, poderá obtê-los simplesmente buscando esses atributos da seguinte maneira:Aqui, em uma transação gerenciada por proxy do Hibernate, o fato de chamar
ticket.getSales()
faz outra consulta para buscar vendas porque você a pediu explicitamente.fonte
Duas coisas que você deve ter
fetch = FetchType.LAZY
.e
fonte
Para aqueles que trabalham com Critérios , descobri que
fiz tudo o que eu precisava tinha feito.
O modo de busca inicial para coleções é definido como FetchMode.LAZY para fornecer desempenho, mas quando preciso dos dados, apenas adiciono essa linha e aprecio os objetos totalmente preenchidos.
fonte
No meu caso, o seguinte código foi um problema:
Porque ele foi desconectado do banco de dados e o Hibernate não recuperou mais a lista do campo quando necessário. Então, eu o inicializo antes de desanexar:
fonte
O motivo é que você está tentando obter a commentList no seu controlador depois de fechar a sessão dentro do serviço.
Acima, o commentList será carregado apenas se a sua sessão de hibernação estiver ativa, o que eu acho que você encerrou no seu serviço.
Portanto, você precisa obter a commentList antes de fechar a sessão.
fonte
Answer
A coleção
comments
na sua classe de modeloTopic
é carregada lentamente, que é o comportamento padrão se você não anotá-la comfetch = FetchType.EAGER
especificamente.É muito provável que o seu
findTopicByID
serviço esteja usando uma sessão do Hibernate sem estado. Uma sessão sem estado não possui o cache de primeiro nível, ou seja, nenhum contexto de persistência. Mais tarde, quando você tentar iterarcomments
, o Hibernate lançará uma exceção.A solução pode ser:
Anotar
comments
comfetch = FetchType.EAGER
Se você ainda deseja que os comentários sejam carregados com preguiça, use as sessões com estado do Hibernate , para que você possa buscar comentários posteriormente, sob demanda.
fonte
No meu caso, eu tinha o mapeamento b / w
A
eB
comoA
temna
DAO
camada, o método precisa ser anotado@Transactional
se você não anotou o mapeamento com Tipo de busca - Ansiosofonte
Não é a melhor solução, mas para aqueles que enfrentam
LazyInitializationException
especialmenteSerialization
isso ajudará. Aqui você verificará as propriedades inicializadas lentamente e as configuraçõesnull
para elas. Para isso crie a classe abaixoDentro da classe Entity, na qual você está tendo propriedades inicializadas preguiçosamente, adicione um método como mostrado abaixo. Adicione todas as suas propriedades de carregamento lento dentro deste método.
Chame esse
checkLazyIntialzation()
método depois em todos os locais em que você está carregando dados.fonte
Olá, Tudo postando muito tarde espero que ajude outras pessoas, Agradecendo antecipadamente a @GMK por este post Hibernate.initialize (object)
quando preguiçoso = "verdadeiro"
Agora, se eu acessar 'set' após o encerramento da sessão, ele lança uma exceção.
Minha solução:
agora posso acessar 'set' mesmo depois de fechar a sessão de hibernação.
fonte
Ainda outra maneira de fazer isso, você pode usar o TransactionTemplate para contornar a busca lenta. Gostar
fonte
O problema é causado porque o código está acessando uma relação JPA lenta quando a "conexão" com o banco de dados é fechada ( contexto de persistência é o nome correto em termos de Hibernate / JPA).
Uma maneira simples de resolvê-lo no Spring Boot é definir uma camada de serviço e usar o
@Transactional
anotação. Essa anotação em um método cria uma transação que se propaga na camada do repositório e mantém aberto o contexto de persistência até o término do método. Se você acessar a coleção dentro do método transacional, o Hibernate / JPA buscará os dados do banco de dados.No seu caso, você só precisa anotar
@Transactional
o métodofindTopicByID(id)
no seuTopicService
e forçar a busca da coleção nesse método (por exemplo, perguntando o seu tamanho):fonte
Para se livrar da exceção de inicialização lenta, você não deve solicitar uma coleção lenta quando operar com um objeto desanexado.
Na minha opinião, a melhor abordagem é usar o DTO, e não a entidade. Nesse caso, você pode definir explicitamente os campos que deseja usar. Como sempre, é o suficiente. Não é necessário se preocupar que algo como jackson
ObjectMapper
ouhashCode
gerado pelo Lombok chame seus métodos implicitamente.Em alguns casos específicos, você pode usar a
@EntityGrpaph
anotação, que permiteeager
carregar, mesmo se houverfetchType=lazy
em sua entidade.fonte
Existem várias soluções para esse problema de inicialização lenta -
1) Altere o tipo de busca de associação de LAZY para EAGER, mas isso não é uma boa prática, pois isso prejudicará o desempenho.
2) Use FetchType.LAZY no Objeto associado e também use a anotação Transacional no método da camada de serviço para que a sessão permaneça aberta e quando você chamar topicById.getComments (), o objeto filho (comentários) será carregado.
3) Além disso, tente usar o objeto DTO em vez da entidade na camada do controlador. No seu caso, a sessão é fechada na camada do controlador. É melhor converter a entidade em DTO na camada de serviço.
fonte
eu resolvi usando a lista em vez de definir:
fonte