Como injetar sessão de banco de dados em lazy load? (Spring e Hibernate)

4 respostas
Fox_McCloud

Bom dia.

Utilizo Spring e Hibernate na minha aplicação (JPA e Annotations).

O DAO é criado usando injeção de:

org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean

com:

adapter org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter

E o AbstractDAO possui a annotation @Transactional

Até aí tudo funcionando redondeenho (k k k k k k)

O pObReMa é: sempre em classes de negócios quando o sistema tenta (via reflexão ou o que quer que seja) acessar um campo anotado com fetch=FetchType.LAZY, ocorre a famosa LazyInitializationException (there is no session or the session was closed).

Já que o Spring gerencia a sessão de base de dados (o DAO não abre a conexão manualmente, o entityManager é utilizado e o Spring se encarrega de abrir / fechar sessão e gerenciar a transação)…

COMO fazer com que o acesso a um getter anotado com lazy load tenha um acesso automático correto a uma sessão válida de conexão com o banco de dados?

Afinal, não faz sentido sequer que exista lazy load se eu sou forçado a acessar o campo quando a conexão ainda está aberta no DAO, perdendo essa funcionalidade em outros momentos onde o sistema precisa acessar esses dados… Seria mais claro eu usar uma query (HQL que seja…) com o bom e velho join, se o lazy não é tão lazy assim uma vez que deve ser acessado no momento do select…

So… may anyone help me? Thanks!!!

4 Respostas

A

Então, este problema de Lazy..... é tenso....

Pelo que percebi, sua aplicação está bem dividida, vc precisa determinar até qual camada irão ocorrer as chamadas de métodos que vão precisar ir no banco e nesta camada (ex. famigerados Services) anotar as classes com @Transactional.

Anote as DAOS e Services ou Repositórios com @Transactional.

@Transactional
[Dao -> Service ou Repositorio] e daqui pra frente, aplique lei de "lei de demeter" para evitar Lazy.....

// Na controller prefira fazer isso

Cliente cliente = clienteService.load(id) ou clienteDao.load(id)
cliente.getName()

Endereco endereco = enderecoService.enderecoDoCliente(cliente) ou enderecoDao.enderecoDoCliente(cliente)
endereco.getRua()

// do q isso

Cliente cliente = clienteService.load(id) ou clienteDao.load(id)

cliente.getName()
cliente.getEndereco().getRua() // problema.....!!!!!!!

Eu particularmente detesto este modelo, mas infelizmente, a tecnologia nos obriga a trabalhar desta maneira, depois que conheci GRAILS, fiquei revoltado com todas estas camadas que vão contra a programação OO, mas........

Fox_McCloud

Hummm… MUITO interessante…

No caso do DAO, todos extendem um AbstractDAO, e anotar APENAS o AbstractDAO com @Transactional funcionou perfeitamente!!

Aqui não fui eu quem fez a arquitetura do sistema, mas felizmente cada camada possui um tipo abstrato básico, então para que eu anote uma camada inteira basta que eu anote esse tipo abstrato básico (ex: AbstractService).

No caso, existe uma camada Converter, que recebe os dados originais das queries (Exemplo: List<ProcessInstance> ) e converte para os objetos que são utilizados no sistema (Ex: List<ProcessoVO> ). Nessa camada ocorrem as exceções, quando o converter tenta efetuar o “de para” de dados relacionados.

Claro que ainda é um problema, porque esse Converter anotado com @Transactional vai forçar que todos os dados relacionados presentes nos VOs do sistema sejam buscados no momento da conversão, ou seja, lá se vai por água abaixo o conceito de lazy load…

Mas eu vou experimentar aqui, muito obrigado pela resposta, se houver mais algum problema correlato eu escrevo neste tópico novamente!

PERGUNTA: qual é a conseqüência (além de, nesse caso, matar o conceito de lazy load e carregar toneladas de dados desnecessários) de anotar uma camada toda com @Transactional? Isso poderia “segurar” muitas conexões com a base de dados abertas, gerando um estouro de pool de conexões ou coisa do tipo? Ou o @Transactional trata de reestabelecer a conexão apenas quando necessário?

Valeu!

A

então, o fato de colocar @Transactional não vai mudar o conceito de Lazy, o que vai acontecer é que a “sessão” vai continuar aberta, sendo assim, evitar a exception…

:wink:

Fox_McCloud

Ah, sim!

O que muda o conceito de lazy é o converter aqui que usa vários getters da entidade que são tabelas relacionadas sem necessidade, rsrsrsrsrsrs!!!

Criado 27 de janeiro de 2011
Ultima resposta 27 de jan. de 2011
Respostas 4
Participantes 2