Problema com LazyInitializationException e EJB3

9 respostas
F

Bom dia,

Estou tendo o seguinte problema:
Tenho um ManagedBean com CDI em ConversationScoped. Esse ManagedBean tem um EJB Stateful injetado nele, sendo que esse EJB possui todos os serviços de CRUD de alguns dados. Além disso, esse EJB tem um EntityManager injetado com PersistenceContext(type= PersistenceContextType.EXTENDED).
Tenho uma página que tem campos ligados à propriedades do objeto ParametrosVingentes. Essas propriedades são carregadas com fetch LAZY.
Quando o ManagedBean é construído, ele inicia a Conversation e chama um método do meu EJB que busca esse objeto, então ele é armazenado em uma variável de instância. Esse objeto tem 4 propriedades que devem ser carregadas com fetch LAZY. Então, quando carrego a página na primeira vez, ele pega o objeto e na hora de renderizar a resposta, os campos pegam esses valores do objeto e carrega normalmente.
Então, de início, ele carrega sem problemas os atributos em LAZY. Inclusive debuguei nos getters e eles são chamados e funcionam. Mas quando eu lanço qualquer evento (seja através de um botão ou qualquer coisa do tipo, ele não recarrega a página com AJAX. Quando olho no console, está a exceção de LazyInitializationException.

Bem, primeiro gostaria de saber se tem algo errado com meu EJB. Ele é Stateful, deveria 'durar' enquanto receber requisições do cliente (nesse caso, o ManagedBean) e meu PersistenceContext está do tipo EXTENDED, o que significa que deveria durar também. Por algum motivo, talvez o EntityManager esteja sendo fechado... ou o EJB que eu chamo está 'morrendo' ou algo do tipo.

Segue os códigos:

@Entity
public class ParametrosVingentes implements Serializable {

    public static final String ID = "settings";

    private static final long serialVersionUID = 1L;
    
    @Id
    private String id;
    @OneToOne
    private ValorHora valorHora;
    @OneToMany
    @JoinTable(
            name="BuscaSistecVingentes",
            joinColumns = @JoinColumn( name="parametros_vingentes_fk"),
            inverseJoinColumns = @JoinColumn( name="agendamento_fk")
    )
    private List<AgendamentoBuscaSistec> agendamentosBuscaSistec;
    @OneToMany
    @JoinTable(
            name="ExportacaoZeusVingentes",
            joinColumns = @JoinColumn( name="parametros_vingentes_fk"),
            inverseJoinColumns = @JoinColumn( name="agendamento_fk")
    )
    private List<AgendamentoExportacaoZeus> agendamentosExportacaoZeus;
    @OneToMany
    @JoinTable(
            name="ImportacaoZeusVingentes",
            joinColumns = @JoinColumn( name="parametros_vingentes_fk"),
            inverseJoinColumns = @JoinColumn( name="agendamento_fk")
    )
    private List<AgendamentoImportacaoZeus> agendamentosImportacaoZeus;

    public ParametrosVingentes() {
	this.id = ID;
    }
//Abaixo estão os getters, setters, equals...
@Stateful
@LocalBean
public class ParametrosService {

    @PersistenceContext(type= PersistenceContextType.EXTENDED)
    private EntityManager entityManager;

    public void cadastrar(ValorHora valorHora){
	ValorHoraDao valorHoraDao = new ValorHoraDao(entityManager);
	valorHoraDao.salvar(valorHora);
    }

    public List<ValorHora> listarValorHora(){
	ValorHoraDao valorHoraDao = new ValorHoraDao(entityManager);
	return valorHoraDao.getAll();
    }

    public boolean excluir(ValorHora valorHora){
	if(valorHora.getRemessas() != null && !valorHora.getRemessas().isEmpty()){
	    return false;
	}
	ValorHoraDao valorHoraDao = new ValorHoraDao(entityManager);
	valorHoraDao.remover(valorHora);
	return true;
    }

    public ParametrosVingentes getParametrosVingentes(){
	return ParametrosUtil.getParametrosVingentes(entityManager);
    }
//Abaixo fica as outras 3 propriedades, da mesma forma
public class ParametrosUtil {

    public static synchronized ParametrosVingentes getParametrosVingentes(EntityManager entityManager){
	ParametrosVingentesDao parametrosVingentesDao = new ParametrosVingentesDao(entityManager);
	ParametrosVingentes parametrosVingentes = parametrosVingentesDao.buscar(ParametrosVingentes.ID);
	if(parametrosVingentes == null){
	    parametrosVingentes = new ParametrosVingentes();
	    //parametrosVingentes.setAgendamentosBuscaSistec(new ArrayList<AgendamentoBuscaSistec>());
	    //parametrosVingentes.setAgendamentosExportacaoZeus(new ArrayList<AgendamentoExportacaoZeus>());
	    //parametrosVingentes.setAgendamentosImportacaoZeus(new ArrayList<AgendamentoImportacaoZeus>());
	    parametrosVingentesDao.salvar(parametrosVingentes);
	}
	return parametrosVingentes;
    }

    public static synchronized ParametrosVingentes atualizarParametrosVingentes(ParametrosVingentes parametrosVingentes, EntityManager entityManager){
	ParametrosVingentesDao parametrosVingentesDao = new ParametrosVingentesDao(entityManager);
	return parametrosVingentesDao.atualizar(parametrosVingentes);
    }
}
<p:fieldset>
		    <h:panelGrid columns="2">
			<h:outputLabel value="Valor da hora:" for="valorHoraVingente" />
			<p:selectOneMenu id="valorHoraVingente" value="#{parametros.parametrosVingentes.valorHora}">
			    <f:selectItem itemLabel="Selecione" itemValue="#{null}" />
			    <f:selectItems value="#{parametros.listaValorHora}" />
			</p:selectOneMenu>
			<h:outputLabel value="Agendamento da Busca do Sistec:" for="agendamentoBuscaSistecVingente" />
			<p:selectManyCheckbox id="agendamentoBuscaSistecVingente" value="#{parametros.parametrosVingentes.agendamentosBuscaSistec}">
			    <f:selectItem itemLabel="Selecione" itemValue="#{null}" />
			    <f:selectItems value="#{parametros.listaAgendamentoBuscaSistec}" />
			</p:selectManyCheckbox>
			<h:outputLabel value="Agendamento da Exportação para o Zeus:" for="agendamentoExportacaoZeusVingente" />
			<p:selectManyCheckbox id="agendamentoExportacaoZeusVingente" value="#{parametros.parametrosVingentes.agendamentosExportacaoZeus}">
			    <f:selectItem itemLabel="Selecione" itemValue="#{null}" />
			    <f:selectItems value="#{parametros.listaAgendamentoExportacaoZeus}" />
			</p:selectManyCheckbox>
			<h:outputLabel value="Agendamento da Importação para o Zeus:" for="agendamentoImportacaoZeusVingente" />
			<p:selectManyCheckbox id="agendamentoImportacaoZeusVingente" value="#{parametros.parametrosVingentes.agendamentosImportacaoZeus}">
			    <f:selectItem itemLabel="Selecione" itemValue="#{null}" />
			    <f:selectItems value="#{parametros.listaAgendamentoImportacaoZeus}" />
			</p:selectManyCheckbox>
		    </h:panelGrid>
		    <p:commandButton value="Atualizar" action="#{parametros.atualizarParametrosVingentes}" update="@form" />
		</p:fieldset>

A seguir está o stacktrace da exceção:

WARNING: failed to lazily initialize a collection, no session or session was closed
org.hibernate.LazyInitializationException: failed to lazily initialize a collection, no session or session was closed
	at org.hibernate.collection.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.java:383)
	at org.hibernate.collection.AbstractPersistentCollection.throwLazyInitializationExceptionIfNotConnected(AbstractPersistentCollection.java:375)
	at org.hibernate.collection.AbstractPersistentCollection.readSize(AbstractPersistentCollection.java:122)
	at org.hibernate.collection.PersistentBag.isEmpty(PersistentBag.java:255)
	at javax.faces.component.UIInput.isEmpty(UIInput.java:1257)
	at javax.faces.component.UIInput.validateValue(UIInput.java:1144)
	at javax.faces.component.UISelectMany.validateValue(UISelectMany.java:581)
	at javax.faces.component.UIInput.validate(UIInput.java:967)
	at javax.faces.component.UIInput.executeValidate(UIInput.java:1233)
	at javax.faces.component.UIInput.processValidators(UIInput.java:698)
	at javax.faces.component.UIComponentBase.processValidators(UIComponentBase.java:1214)
	at javax.faces.component.UIComponentBase.processValidators(UIComponentBase.java:1214)
	at org.primefaces.component.fieldset.Fieldset.processValidators(Fieldset.java:197)
	at javax.faces.component.UIForm.processValidators(UIForm.java:253)
	at javax.faces.component.UIComponentBase.processValidators(UIComponentBase.java:1214)
	at javax.faces.component.UIComponentBase.processValidators(UIComponentBase.java:1214)
	at javax.faces.component.UIViewRoot.processValidators(UIViewRoot.java:1172)
	at com.sun.faces.lifecycle.ProcessValidationsPhase.execute(ProcessValidationsPhase.java:76)
	at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:101)
	at com.sun.faces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:118)
	at javax.faces.webapp.FacesServlet.service(FacesServlet.java:593)
	at org.apache.catalina.core.StandardWrapper.service(StandardWrapper.java:1539)
	at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:281)
	at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:175)
	at org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:655)
	at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:595)
	at com.sun.enterprise.web.WebPipeline.invoke(WebPipeline.java:98)
	at com.sun.enterprise.web.PESessionLockingStandardPipeline.invoke(PESessionLockingStandardPipeline.java:91)
	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:162)
	at org.apache.catalina.connector.CoyoteAdapter.doService(CoyoteAdapter.java:330)
	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:231)
	at com.sun.enterprise.v3.services.impl.ContainerMapper.service(ContainerMapper.java:174)
	at com.sun.grizzly.http.ProcessorTask.invokeAdapter(ProcessorTask.java:828)
	at com.sun.grizzly.http.ProcessorTask.doProcess(ProcessorTask.java:725)
	at com.sun.grizzly.http.ProcessorTask.process(ProcessorTask.java:1019)
	at com.sun.grizzly.http.DefaultProtocolFilter.execute(DefaultProtocolFilter.java:225)
	at com.sun.grizzly.DefaultProtocolChain.executeProtocolFilter(DefaultProtocolChain.java:137)
	at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:104)
	at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:90)
	at com.sun.grizzly.http.HttpProtocolChain.execute(HttpProtocolChain.java:79)
	at com.sun.grizzly.ProtocolChainContextTask.doCall(ProtocolChainContextTask.java:54)
	at com.sun.grizzly.SelectionKeyContextTask.call(SelectionKeyContextTask.java:59)
	at com.sun.grizzly.ContextTask.run(ContextTask.java:71)
	at com.sun.grizzly.util.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:532)
	at com.sun.grizzly.util.AbstractThreadPool$Worker.run(AbstractThreadPool.java:513)
	at java.lang.Thread.run(Thread.java:722)

Agradeço desde já.

9 Respostas

Hebert_Coelho

Como está seu MB? Você está injetando ou fazendo Lookup?

Eu li num livro que seu EJB seria uma saída para LazyEx. colocar Statefull/Extended, mas nesse exemplo ele utiliza injeção.

Pra que que serve o ParametrosUtil?

F

jakefrog:
Como está seu MB? Você está injetando ou fazendo Lookup?

Eu li num livro que seu EJB seria uma saída para LazyEx. colocar Statefull/Extended, mas nesse exemplo ele utiliza injeção.

Pra que que serve o ParametrosUtil?

Alí no código tem o ManagedBean também. Eu estou injetando com a anotação @EJB. Meu EJB é Stateful e o PersistenceContext é Extended, acho que teoricamente deveria funcionar.

Como eu preciso ter apenas um objeto de ParametrosVingentes salvo no Banco de Dados, criei essa solução: um ID fixo que sempre é colocado no construtor e criei esse ParametrosUtil para ter um método static synchronized para pegar o objeto ou criar, caso ele não exista ainda. Coloquei dessa forma para evitar de que ele possa tentar criar de novo.

Hebert_Coelho

Cara, tenta tirar o método de static e passa para normal mesmo.

F

Desculpa, mas qual o sentido disso? Não vejo como isso poderia mudar no problema…

Hebert_Coelho

Um método static pertence a classe toda e o JSF (apenas por exemplo) não conseguia localizar método estático (agora eu não sei se consegue, mas antes ele não conseguia).

Não sei como que o EJB se comporta tendo seu método como estático.

Só tentei ajudar. [=

F

jakefrog:
Um método static pertence a classe toda e o JSF (apenas por exemplo) não conseguia localizar método estático (agora eu não sei se consegue, mas antes ele não conseguia).

Não sei como que o EJB se comporta tendo seu método como estático.

Só tentei ajudar. [=

Obrigado pela ajuda.
Já testei onde acontece o problema… no EJB a entidade ainda chega normal. Coloquei um get para as coleções que são carregadas com LAZY dentro do EJB e funcionou. O problema é depois que sai do EJB. Tenho a impressão que depois que termina o método do EJB, apesar do EJB continuar lá com o EntityManager, acho que ele está dando um clear() no EntityManager ou algo do tipo.

F

O pior de tudo é que na primeira requisição para a página, funciona normalmente.

INFO: Hibernate: select parametros0_.id as id7_1_, parametros0_.valorHora_id as valorHora2_7_1_, valorhora1_.id as id5_0_, valorhora1_.dataCriacao as dataCria2_5_0_, valorhora1_.valor as valor5_0_ from ParametrosVingentes parametros0_ left outer join ValorHora valorhora1_ on parametros0_.valorHora_id=valorhora1_.id where parametros0_.id=? INFO: Hibernate: select agendament0_.parametros_vingentes_fk as parametros1_7_1_, agendament0_.agendamento_fk as agendame2_1_, agendament1_.id as id2_0_, agendament1_.agendamento as agendame2_2_0_, agendament1_.dataCriacao as dataCria3_2_0_ from BuscaSistecVingentes agendament0_ inner join AgendamentoBuscaSistec agendament1_ on agendament0_.agendamento_fk=agendament1_.id where agendament0_.parametros_vingentes_fk=? INFO: Hibernate: select agendament0_.parametros_vingentes_fk as parametros1_7_1_, agendament0_.agendamento_fk as agendame2_1_, agendament1_.id as id0_0_, agendament1_.agendamento as agendame2_0_0_, agendament1_.dataCriacao as dataCria3_0_0_ from ExportacaoZeusVingentes agendament0_ inner join AgendamentoExportacaoZeus agendament1_ on agendament0_.agendamento_fk=agendament1_.id where agendament0_.parametros_vingentes_fk=? INFO: Hibernate: select agendament0_.parametros_vingentes_fk as parametros1_7_1_, agendament0_.agendamento_fk as agendame2_1_, agendament1_.id as id1_0_, agendament1_.agendamento as agendame2_1_0_, agendament1_.dataCriacao as dataCria3_1_0_ from ImportacaoZeusVingentes agendament0_ inner join AgendamentoImportacaoZeus agendament1_ on agendament0_.agendamento_fk=agendament1_.id where agendament0_.parametros_vingentes_fk=? INFO: Hibernate: select valorhora0_.id as id5_, valorhora0_.dataCriacao as dataCria2_5_, valorhora0_.valor as valor5_ from ValorHora valorhora0_ INFO: Hibernate: select agendament0_.id as id2_, agendament0_.agendamento as agendame2_2_, agendament0_.dataCriacao as dataCria3_2_ from AgendamentoBuscaSistec agendament0_ order by agendament0_.dataCriacao DESC INFO: Hibernate: select agendament0_.id as id0_, agendament0_.agendamento as agendame2_0_, agendament0_.dataCriacao as dataCria3_0_ from AgendamentoExportacaoZeus agendament0_ order by agendament0_.dataCriacao DESC INFO: Hibernate: select agendament0_.id as id1_, agendament0_.agendamento as agendame2_1_, agendament0_.dataCriacao as dataCria3_1_ from AgendamentoImportacaoZeus agendament0_ order by agendament0_.dataCriacao DESC

Ele gera todos os SELECTs normalmente. Mas, nas requisições posteriores para alguma ação, ele da LazyInitializationException.

F

Eu mudei o EJB para pegar o PersistenceUnit e eu peguei o EntityManager e operei ‘manualmente’ as transações.
O problema continuou.

Então, concluo que o problema é a instância do EJB. Apesar do mesmo ser anotado com @Stateful, ele parece estar se perdendo. Se alguém ver algum erro que não estou vendo, agradeço se ajudar.

F

fernando.camargo:
Eu mudei o EJB para pegar o PersistenceUnit e eu peguei o EntityManager e operei ‘manualmente’ as transações.
O problema continuou.

Então, concluo que o problema é a instância do EJB. Apesar do mesmo ser anotado com @Stateful, ele parece estar se perdendo. Se alguém ver algum erro que não estou vendo, agradeço se ajudar.

Testei com um contador. O Session Bean não está perdendo o estado. Então já não tenho a mínima ideia do que pode ser…

Criado 6 de janeiro de 2012
Ultima resposta 11 de jan. de 2012
Respostas 9
Participantes 2