alguém poderia me indicar uma solução mais elegante ao Open Session in View ?
Seria melhor você especificar o problema que voce passa. O ideal é nao precisar de nada desse tipo.
Já que você tá usando Java EE, que tal usar Container Managed Transactions?
Você define o método do controller/service como REQUIRED
e marca todos os outros como MANDATORY
. Assim, toda operação de um controller/service é tratada de forma atômica, em relação às outras e você não precisa nem encostar em código de transação.
meu problema é o seguinte estou trabalhando com hibernate e com o pattern Open Session in View. o que funciona muito bem em determinados momentos mas que em alguns momentos acontecem muitos erros de LazyInitializationException.
eu gostei da sugestão do lvbarbabora mas se existirem outras podem comentar
Quando você faz uma busca e o Hibernate te devolve objetos, ele te devolve proxies (através de reflection), e não os objetos reais. Quando você acessa um método get
, o proxy faz com que o framework emita uma nova query para o DB para popular a devida referência e te retornar no get
. Para que isso ocorra, é necessário haver uma seção aberta. Eu não sei como é o default do Hibernate, mas eu acredito que as durações da seção e da transação sejam análogas: quando a transação termina, a seção é fechada.
Quando você chama um get
no proxy sem que aquele dado esteja carregado e fora de uma seção, o proxy vai tentar contatar o framework e vai perceber que não há seção. Por isso uma LazyInitializationException
é lançada.
Você pode fazer com que a seção continue aberta independente da presença de transações ou não. Não sei como fazer isso especificamente no Hibernate, mas no JPA existe o Extended Persistence Context feito exatamente para isso.
Outra solução é simplesmente mandar para a view (que eu acredito que é o lugar onde a exception está acontecendo) todos os dados que ela precisa, antes de encerrar a seção. Para isso, você pode ou chamar os métodos de lazy loading antes de fechar a seção (só chama sem capturar o retorno), ou então setar a propriedade como EAGER ao invés de LAZY.
realmente você está correto, a solução Open Session in View não é ruim mas estou tendo problemas (provavelmente por minha culpa) então estava querendo outras alternativas vou estudar essas que você me passou para ver se me atende.
“Open Sessino in View” é apelação, mas bem ou mal é uma forma de remediar o seu problema de arquitetura.
Se quiser trabalhar com hibernate com o mínimo de eficiência, então pelo menos utilize os recursos dele para gerar queries sob controle. Pode utilizar HQL/JPQL ou Criteria, aplicando “fetch” para redefinir os relacionamentos mapeados de lazy para eager. Assim evita inclusive o famoso problema de n+1 queries dentro de uma mesma requisição, com várias idas ao servidor de banco de dados sem necessidade, o que prejudica performance. Então, você resolve de uma vez ou com um mínimo de idas para pegar o que precisa do banco e atender de forma eficiente a requisição web. Com isso, durante o processamento da view não precisa mais ter a conexão aberta para ficar pipocando os lazys, podendo fechar o mais cedo possível.
Sei que HQL/JPQL/JPQ… e principalmente Criteria são horríveis de se trabalhar, mas Hibernate é a ferramenta que você escolheu, então terá arcar com os custos para entregar resultado eficiente. Eu pessoalmente prefiro trabalhar diretamente com SQL e sem Hibernate. Em último caso você também pode utilizar SQL com Hibernate.
Dá uma olhada:
Sobre HQL: https://docs.jboss.org/hibernate/orm/5.2/userguide/html_single/chapters/query/hql/HQL.html