Dúvidas sobre o funcionamento do Hibernate

3 respostas
K

Olá pessoal,

Eu acho o Hibernate um framework ORM fenomenal, na verdade o melhor até o momento na minha humilde opnião, mas tenho algumas dúvidas sobre o seu funcionamento.

Existe um problema com Lazy Loading que já vi muita gente questionando e nenhuma solução realmente elegante, que é o problema de objeto detached da hibernate session quando esse objeto atravessa uma requisição web. Por exemplo, na requisição A eu carrego o objeto A e quando o web server enviar a resposta ao cliente a hibernate session será fechada, sendo que esse objeto A ficou guardado na http session ou algo equivalente, e quando na requisição B eu tentar acessar um lazy object eu vou tomar uma exceção “failed to lazily initialize a collection…: …no session or session was closed”.
Isso é fácil de entender, a hibernate session a qual o objeto A estava ligado foi fechada e agora ele não tem mais como se comunicar com o banco, a não ser que eu o realoque numa hibernate session nova(o que pode me acarretar outros problemas). Aí vem minha dúvida, o pessoal da Hibernate Team ao invés de sempre lançar uma exception não poderia colocar uma configuração que ao tentar acessar um lazy object, que pertence a um objeto desalocado de uma sessão ativa, criasse uma sessão trouxesse as informações e fechasse a sessão em seguida?
Com certeza devem haver muitos problemas em se fazer isso já que o pessoal do Hibernate não o fez assim, mas eu não consigo ver esses problemas, vocês saberiam o por que sempre lançar uma exception?

Já muitos exemplos de DAOs implementados com hibernate onde para cada método que faz alguma operação no banco, a hibernate session é aberta, utilizada e fechada em seguida, ou seja, a sessão a qual um objeto foi carregado estará sempre fechada. É claro que podemos mudar isso e deixar a sessão aberta por mais tempo, mediante alguma condição para fechá-la, mas isso acarretaria outros problemas que prefiro não comentar neste momento.

Não me agrada a idéia de inicializar o objeto lazy assim que entidade pai for carregada, pois eu teria que saber de ante-mão se aquele objeto lazy vai ser utilizado ou não e não sempre é possível saber, às vezes pode ser utilizado como às vezes não, vai depender muito do fluxo que o usuário percorrer, então às vezes estaria sendo feita uma carga de dados desnecessária.

Como o post já está grande, vou deixar outras coisas para outras dicussões, pois esta dúvida é a mais importante no momento.

3 Respostas

andreiribas

cara já existe o que você prentede fazer.
O Spring tem um filtro que chama OpenSessionInView, que serve somente para fechar a session do hibernate depois que a página tiver sido carregada para o usuário, assim não tem mais o problema de lazy-load.

K

E aí André,

quando você fala do OpenSessionInView você está falando desse artigo: Open Session in View(http://www.hibernate.org/43.html)?
Eu cheguei a ler esse artigo, tem algumas estratégias interessantes, principalmente a “What about the extended Session pattern for long Conversations”, mas existe um problema que eu considero perigoso.

Pelo código apresentado no artigo, quando há uma requisição, é aberta uma hibernate session e colocada na http session até que uma flag de fim da conversação seja setada, indicando que a sessão seja fechada, feito commit e tudo mais. Até aí tudo bem, vou tentar descrever o problema que imagino e vocês opinem se isso é verdade, se é perigoso ou é pura imaginação minha.

Vamos dizer que minha aplicação segue a seguinte estrutura:

Candidato:
- Dados Pessoais (candidato1.jsp)
- Habilidades Profissionais (candidato2.jsp)
- Experiências Profissionais (candidato3.jsp)

Oportunidade:
- Dados da vaga (oportunidade.jsp)

Bom, nós temos duas funcionalidades, certo? No caso de Oportunidade, quando o usuário fizer a requisição para edição de uma Oportunidade do sistema, o filtro OpenSessionInView irá abrir a hibernate session, o sistema irá carregar uma instância de Oportunidade e essa instância está “alocada” naquela hibernate session aberta pelo filtro, certo? Até tudo bem, pois o processo de edição da oportunidade se dá por um único passo, quando o usuário clicar em Salvar as alterações o flag da conversação será setado indicando que as alterações devem ser salvar e comitadas para o DB.

Mas agora imagine outro cenário, o usuário inicia o processo de alteração de um Candidato, o filtro inicia a hibernate session, o sistema carrega a instância do candidato e o mesmo é guardado na http session ou equivalente, o usuário altera os dados pessoais na primeira página, o filtro não vai iniciar uma outra session visto que eu não setei o fim da conversação, o hibernate session que foi guardada na http session é carregada e eu continuo a alteração do candidato agora alterando suas habilidades profissionais que por um acaso é uma coleção lazy qualquer, a coleção será carregada normalmente, pois o a hibernate session ainda está viva, certo? Então eu finalmente eu vou para o terceiro passo que será a alteração das experiências profissionais, a hibernate session ainda está viva lá aguardando eu falar que é o fim, mas por um motivo qualquer eu como usuário que estava fazendo as alterações do candidato me arrependi de tudo isso e saí da funcionalidade simplesmente clicando no link que leva para a tela de Oportunidades e iniciei a alteração de uma Oportunidade, quando eu clicar em Salvar as alterações da oportunidade e a hibernate session que foi iniciada lá no processo de alteração de candidato for fechada e comitada, todas as alterações feitas na Oportunidade serão comitadas para o banco, ok? Mas tenho um problema sério nesse momento, pois as alterações feitas nos Dados Pessoais e Experiências Profissionais do candidato que foram alteradas porém não confirmadas, já que o usuário abortou a operação pelo meio simplesmente saindo da funcionalidade, também serão refletidas no DB.

Esse ponto é que é o problema, como controlar isso? Se o usuário não confirmar as alterações, as alterações não deveriam ir para o banco, mas como as entidades quando estão ligadas a hibernate session são alteradas, essas alterações são enviadas para o banco sozinhas quando um Flush é feito na hibernate session.

Espero que tenha conseguido explicar o que tanto me incomoda, infelizmente não tenho com quem debater esse problema, somente vocês aqui do fórum.
Por favor, gostaria da opnião de vocês.

K

Opa, nada? Todo mundo sem idéias? Ou eu estou tentando fazer besteira? :-o

Criado 3 de maio de 2008
Ultima resposta 8 de mai. de 2008
Respostas 3
Participantes 2