Solucionado (ver solução)
Solucionado
(ver solução)
8
respostas

Erro quando fecho o EntityManager.

Pessoal eu fiquei com uma dúvida devo ou não fechar o EntityManager?

Eu estou fazendo uma API Rest bem simples e quando eu faço a primeira requisição para o servidor ele funciona tranquilamente, seja qual for a operação insert, select etc, mas na segunda requisição ele da erro Session/EntityManager is closed

Se eu não fechar o EntityManager ele funciona de boa, mas devo deixar aberto? é isso mesmo que deve ser feito?

vou postar o código aqui caso ainda reste dúvida.


public class DiscenteDAO {

    private EntityManager em  = JPAUtil.getEntityManager();


    public boolean save(Discente discente) throws Exception{

        try {
            em.getTransaction().begin();
            em.persist(discente);
            em.getTransaction().commit();
            em.close(); // se eu comentar isso o erro para de acontecer
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }


    public Discente get(Integer id){

        em.getTransaction().begin();
        Discente discente = em.find(Discente.class, id);
        em.getTransaction().commit();
        em.close(); // se eu comentar isso o erro para de acontecer
        return discente;
    }

}

JPAUtil

public class JPAUtil {

    private static EntityManager em = Persistence.createEntityManagerFactory("odonto").createEntityManager();

    public static EntityManager getEntityManager(){
        return em;
    }
}

Isso é muito importante para mim pessoal, e eu preciso de uma explicação boa sobre isso, por que isso faz parte de um projeto real

8 respostas
solução!

Ramires, tudo certo, cara? =)

Vamos lá... Sua classe DiscenteDAO possui um atributo privado, que é o EntityManager. Repare que você já atribui um valor à ele, na própria declaração de atributo! Dessa forma, toda vez que você instanciar um objeto do tipo DiscenteDAO, você criará, também, um EntityManager.

Agora, vamos supor que em uma request você queira inserir um objeto no BD e, logo em seguida, mas na mesma requisição, você queria fazer um select, para buscar alguma informação. Para isso, você teria que invocar o método save() e o método get()... O problema é que você está fechando o EntityManager no momento em que qualquer um dos métodos é executado. Dessa forma, você não consegue reaproveitar seu DAO, você teria que instanciar outro, sacou? =|

Você está usando o padrão MVC? Uma solução é criar uma classe que implemente javax.servlet.Filter e abrir e fechar o EntityManager lá... Mas, acredito que a melhor solução seja utilizar o Spring e deixá-lo controlar as transações, com @Transcional, sacou? Dessa forma, você pode criar um Controller que, em cada método com essa anotação, ele colocará dentro de uma transação! =D

Conseguiu entender o problema e, uma possível solução? =)

Espero que tenha conseguido lhe ajudar, mas qualquer coisa não deixe de postar por aqui, no fórum, para que possamos ajudá-lo, ok?

Abraço e bons estudos,

Fábio

Fabio aproveitando sua resposta posso perguntar uma coisa?

Alisson,

Manda aí. Rs. Se eu souber responder... Rs.

Fábio

Qual a difrença do CDI e do EJB? no meu projeto sempre uso CDI e o EJB? PARA OQUE seria?

Alisson,

Infelizmente essa eu vou ficar te devendo algo mais concreto e conclusivo... =|

Os dois realmente, são muito próximos, entretanto, se não me engano, EJB pode ser um pouco mais poderoso. Já vi gente comentando que, no futuro, pode ser que CDI venha a substituir os EJBs, devido à alta complexidade destes...

Mas, dei uma pesquisadinha aqui, dá uma olhada nessas duas threads do StackOverflow:

A segunda é um pouco mais completa! Talvez lhe ajude em alguma coisa... =)

Fábio

Ah cara muito obrigado, deu para entender um pouco mais, vlw mesmo!

Boa tarde Fábio!

Muito obrigado pela sua resposta, e respondendo a sua pergunta eu não uso MVC pois minha aplicação é uma API REST estou usando um micro framework spark que roda um jetty embedded.

Você me sugeriu criar uma classe que estendesse Filter, no caso do spark já existe um método estático before que é invocado antes de qualquer requisição, baseado nessas informações eu gostaria de fazer mais duas perguntas.

1 - Sua sugestão fere alguma boa prática? "ex. inconsistência, performance ou segurança?"

2 - Se não como eu devo implementar isso? você se incomoda de me mostrar um código simples de como fazer?

Para não deixar o EntityManager aberto eu fiz o seguinte.

    public Discente get(Integer id){
        EntityManager em = new JPAUtil().getEntityManager();
        em.getTransaction().begin();
        Discente discente = em.find(Discente.class, id);
        em.getTransaction().commit();
        em.close();
        return discente;
    }

note que eu estou criando um em a cada nova requisição, isso para todo método do DAO, minha dúvida é se isso não pode gerar inconsistência de dados.