Erro com Hibernate + Spring - "could not initialize proxy - the owning Session was closed"

17 respostas
davidbuzatto

Olá!

Pessoal, estou usando o Spring para me ajudar a trabalhar com o Hibernate, mas estou precisando criar um método para excluir o relacionamento entre duas entidades e depois remontar esse relacionamento. Na aplicação (web) eu tenho duas listas, onde uma contem os Subtemas e na outra os Subtemas que estão relacionados a um Tema. Quando eu submeto o formulário, eu envio os ids dos Subtemas. No servidor, todos os Subtemas relacionados ao Tema são removidos, os ids recebidos são iterados, faz-se uma pesquisa para cada id e vou adicionando de novo no Tema. Por fim, atualizo o Tema.
Meu problema está na hora que tento alterar algo no Tema. O primeiro erro vem quando eu tento limpar o Set que mantém os Subtemas no tema. Vejam o código:

hTemplate é um HibernateTemplate e idsSubtemasRelacionados é uma String que contém todos os ids dos Subtemas a serem relacionados, separados por traço.

if ( !idsSubtemasRelacionados.equals( "" ) ) {

    o = ( Tema ) hTemplate.load( Tema.class, 
            Long.parseLong( request.getParameter( "id" ) ) );

    // retira todos os subtemas
    // o erro acontece aqui, quanto teto mudar algo do objeto recebido.
    o.getSubtemas().clear();

    String[] idsSubtemas = idsSubtemasRelacionados.split( "-" );

    for ( String i : idsSubtemas ) {

        // pesquisa cada subtema e insere no tema
        o.getSubtemas().add( ( Subtema ) hTemplate.load( Subtema.class, Long.parseLong( i ) ) );

    }

    hTemplate.update( o );

}

Tema e Subtema estão usando um relacionamento ManyToMany, ou seja, a tabela que liga os dois é gerada pelo Hibernate e cada um está mapeado dentro do outro por um Set. O método equals está implementado tanto em Tema quanto em Subtema.

Abraço!

17 Respostas

davidbuzatto

Faltou falar do erro…

Então, no e.getSubtemas().clear() é gerada uma excessão.

could not initialize proxy - the owning Session was closed org.hibernate.proxy.AbstractLazyInitializer.initialize(AbstractLazyInitializer.java:60) org.hibernate.proxy.AbstractLazyInitializer.getImplementation(AbstractLazyInitializer.java:111) org.hibernate.proxy.pojo.cglib.CGLIBLazyInitializer.invoke(CGLIBLazyInitializer.java:140) br.com.ynner.ynnerlib.entidades.Tema$$EnhancerByCGLIB$$a798a758.getSubtemas(<generated>) br.com.ynner.ynnerlib.servlets.TemaServlet.processRequest(TemaServlet.java:66) << LINHA DO e.getSubtemas.clear() br.com.ynner.ynnerlib.servlets.TemaServlet.doPost(TemaServlet.java:100) javax.servlet.http.HttpServlet.service(HttpServlet.java:709) javax.servlet.http.HttpServlet.service(HttpServlet.java:802)

Estou usando Servlets devido a especificação que me foi passada.

Obrigado!

A

davidbuzatto ,

poderia mostrar o mapeamento das entidades envolvidas?

Mas adiantando, isso parece ser algo relacionado a “mappedBy” ou “inverse”… Mas acho que vendo os mapeamentos, podemos ajudar melhor… :slight_smile:

Abraço…

davidbuzatto

Olá!

Estão ai os mapeamentos (estou usando annotations)

@Entity
public class Subtema {
    
    @Id
    @GeneratedValue
    private long id;
    
    @Length( max = 50 )
    @NotNull
    @NotEmpty
    private String descricao;

    @ManyToMany
    private Set< Tema > temas;
    
    @ManyToMany
    private Set< Materia > materias;

}

@Entity
public class Tema {
    
    @Id
    @GeneratedValue
    private long id;
    
    @Length( max = 50 )
    @NotNull
    @NotEmpty
    private String descricao;

    @ManyToMany( mappedBy = "temas" )
    private Set< Subtema > subtemas;
    
    @ManyToMany
    private Set< Materia > materias;

}

Já inverti o mapeamento (usando o mappedBy invertido, ou seja, dentro da entidade Tema), mas tbm não funcionou.

A

Certo…

Tente inicializar seus atributos

private Set<Subtema> subtemas = new HashSet<Subtema>();

Ou ao invés de dar um .clear(), vc não faz o seguinte:

o.setSubtemas(new HashSet<Subtema>());

Ou outra implementação da interface Set…

davidbuzatto

Olá!

Obrigado pelas dicas, eu testei as mesmas mesmo tendo certeza que não é isso.
O problema está que o Spring não está mantendo a sessão aberta, pois se eu altero algo no objeto ele não deixa, isso está ligado a qualquer atributo e não só ao Set. Enfim, obrigado pela ajuda.

Se alguém tiver outra sugestão estou aguardando.

Até mais!

davidbuzatto

Andei pesquisando, e como o próprio erro diz, é pq a sessão do Hibernate já está fechada, e como estou usando lazy loading dá esse erro. O mais estranho é que mudei todos os relacionamentos para FetchType.EAGER e mesmo assim não funciona, o erro permanece.
Teria como configurar para que no Spring a sessão fique aberta e depois eu a feche?

davidbuzatto

Já estou quase montando a entidade fraca na mão :smiley:
Ninguém tem uma solução? Eu não queria abrir mão do Spring :frowning:

A

davidbuzatto:
Já estou quase montando a entidade fraca na mão :smiley:
Ninguém tem uma solução? Eu não queria abrir mão do Spring :(

Amigo, o Spring resolve este problema. Tudo que tem que fazer é injetar a session por ele. Fazer manualmente é muito tosco e vira um baita trabalho desnecessário.
Vá ao site do Urubatan:

www.urubatan.com.br

Lá existem exemplos com Spring e o Annotation dele. Muito bom e resolve seu problema.

Abraços e bons códigos ai.

davidbuzatto

ajaxinaction:
davidbuzatto:
Já estou quase montando a entidade fraca na mão :smiley:
Ninguém tem uma solução? Eu não queria abrir mão do Spring :(

Amigo, o Spring resolve este problema. Tudo que tem que fazer é injetar a session por ele. Fazer manualmente é muito tosco e vira um baita trabalho desnecessário.
Vá ao site do Urubatan:

www.urubatan.com.br

Lá existem exemplos com Spring e o Annotation dele. Muito bom e resolve seu problema.

Abraços e bons códigos ai.

Valeu! Vou dar uma olhada!

rodrigo_corinthians

Procura sobre OpenSessionInViewFilter ou melhor usa a solução que o kenobi postou.

http://guj.com.br/posts/list/43846.java#231495

davidbuzatto

Valeu rodrigo, agora está dando certo!
Só que não está atualizando no banco :frowning:
Mas o erro foi embora :smiley:
Abraço!

davidbuzatto

Bem… Não funcionou…
Testei os cadastrados que já estava funcionando, e agora eles pararam de funcionar, os objetos não são mais atualizados tbm…

davidbuzatto

Consegui!

Usando o OpenSessionInViewFilter (post do Kenobi) eu tive que a partir do meu Hibernate Template obter a sessão e abrir uma transação e dar commit na mesma. Porque o transaction manager não funciona? Fui obrigado a criar, iniciar e comitar a transação.

Outra coisa que estava errada era o mapeamento que estava invertido em TODOS os meus relacionamentos :D, mas isso não tem nada haver com o “erro” do Spring.

Valeu pessoal!

jgbt

davidbuzatto:
Porque o transaction manager não funciona? Fui obrigado a criar, iniciar e comitar a transação.

vc configurou a transação no applicationContext?

[]´s

davidbuzatto
jgbt:
davidbuzatto:
Porque o transaction manager não funciona? Fui obrigado a criar, iniciar e comitar a transação.
vc configurou a transação no applicationContext?

[]´s

Criei sim.

Olha só:

.
.
.
<!-- Data Source -->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">

    <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
    <property name="url" value="jdbc:mysql://localhost/banco"/>
    <property name="username" value="usuario"/>
    <property name="password" value="senha"/>
    <property name="initialSize" value="5"/>
    <property name="maxActive" value="10"/>

</bean>

<!-- Session Factory -->
<bean id="sessionFactory"
        class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">

    <property name="dataSource" ref="dataSource" />

    <!-- Classes -->
    <property name="annotatedClasses">
        <list>
            <value>entidades....</value>
        </list>
    </property>

    <property name="hibernateProperties">
        <props>
            <!-- Buscando no arquivo de properties -->
            <prop key="hibernate.dialect">${hibernate.dialect}</prop>
        </props>
    </property>
</bean>

<!-- Gerenciador de Transações para o Hibernate -->
<bean id="transactionManager"
        class="org.springframework.orm.hibernate3.HibernateTransactionManager">
    <property name="sessionFactory" ref="sessionFactory"/>
</bean>

<!-- Configurando o DAO genérico -->
<bean id="dao" class="br.edu.unifeob.sgp.daos.Dao">
    <property name="sessionFactory" ref="sessionFactory" />
</bean>
.
.
.

Faltou algum detalhe?

jgbt

sim :smiley:

vc precisa dizer p/ o Spring qual objeto/metodo precisa de transação e qual tipo de transação vc vai aplicar.
de uma olhada nesses links:

http://static.springframework.org/spring/docs/2.0.x/reference/orm.html#orm-jpa-tx
http://www.onjava.com/pub/a/onjava/2005/05/18/swingxactions.html
http://static.springframework.org/spring/docs/1.2.x/reference/transaction.html

qualquer coisa que não entender avisa.

[]´s

davidbuzatto

Hummm entendi!

Vou dar uma olhada!

Obrigado!

Criado 25 de novembro de 2007
Ultima resposta 29 de nov. de 2007
Respostas 17
Participantes 5