Boa noite pessoal, uma dúvida que sempre tive com relação ao EntityManager foi sobre seu escopo em um ambiente J2EE não gerenciado.
Abrir e fechar a cada transação? Abrir e fechar a cada operação de negócio? Abrir e fechar a cada Requisição HTTP?
Andei lendro sobre isso mas não encontrei uma resposta clara (ou não consegui entender ).
Suponha que tenho uma aplicação com struts 2 e hibernate, e quando vou persistir o objeto X a seguinte sequência de acontende:
action -> bo -> dao
Bem, se eu fechar a cada transação, se o objeto X possuir uma lista LAZY e eu fizer X.getLista() na minha action vou obter um org.hibernate.LazyInitializationException.
Além disso este modo me traria outro problema:
Se uma operação de negócios envolver várias entidades e ocorrer um erro na persistência de alguma, um rollback não teria o resultado esperado, pois o escopo não envonve a operação toda, ele é para cada entidade.
Neste caso uma solução seria criar o entiry manager na camada BO e injetálo no DAO?
Ou ainda utilizar somente um EntityManager para a requisição http?
Atualmente estou abrindo um EntityManager para cada dao mas não estou fechando eles, isso é aceitável?
Existem muitos frameworks para lhe ajudar com JPA/Hibernate, como o Seam por exemplo. Ele faz gerenciamento de transação, injeta EntityManager controlando todo seu ciclo de vida, sem vc precisar se preocupar em finalizar o EntityManager e tbm prevê a aplicação contra erros do tipo LIE nas páginas, sem vc ter que implementar o pattern que sugeri acima. Leia um pouco aqui: http://docs.jboss.org/seam/2.1.2/reference/en-US/html/persistence.html
Se vc não usa framework algum com o EntityManager, cuidado, vc NÃO deve manter seus EntityManagers abertos. Se vc fazer isso, em pouco tempo vc vai ter sérios problemas com pool de conexões, uma vez que vc obtem uma sessão com o banco e não devolve para o pool. A recomendação é que vc trabalhe com um entitymanager ativo por “Unit of Work”, ou seja, a atomicidade de uma operação do usuário com o sistema… geralmente em aplicações web isso se dá em um ciclo de request e response. Se sua transaçao é maior do que isso, vc pode armazenar o contexto de seu entitymanager provisóriamente na sessão web, e depois fecha-lo no final da transação. Frameworks como o Seam e o SpringWebFlow fazem parecido quando precisam lidar com Transações Extendidas e podem ajudar tbm nestes casos.
Um livro que sempre indico, qual aborda este e outros temas relevantes sobre JPA e Hibernate é o JavaPersistence With Hibernate (ele tbm possui uma versão traduzida). Ele explica em detalhes a abordagem JavaSE e Java EE para se trabalhar com JPA.