JPA - EntityManager e Singleton

10 respostas
Java_Player

Olá,

Em todo exemplo que eu vejo de JPA, o EntityManagerFactory é um singleton (ou injetado), enquanto que o EntityManager é sempre instanciado um novo a cada chamada de método service.

Por que o EntityManager não pode também ser um Singleton (ou injetado) ??

Exemplo:

//imports

public class BasicService {

    protected static EntityManagerFactory entityManagerFactory;
    protected static EntityManager entityManager;
    protected static EntityTransaction transaction;
    
    static {
        entityManagerFactory = Persistence.createEntityManagerFactory("persistenceUnit");
        entityManager = entityManagerFactory.createEntityManager();
        transaction = entityManager.getTransaction();
    }

}



//imports

public class UsuarioService extends BasicService {

    public void add(Usuario usuario) throws Exception {

        try {
            transaction.begin();
            entityManager.persist(usuario);
            transaction.commit();
        } catch (Exception e) {
            transaction.rollback();
            throw e;
        }

    }
    
    public void update(Usuario usuario) throws Exception {

        try {
            transaction.begin();
            entityManager.merge(usuario);
            transaction.commit();
        } catch (Exception e) {
            transaction.rollback();
            throw e;
        }

    }

}

Eu coloquei desta forma, e está funcionando, além de estar mais rápido do que quando eu instancio o EntityManager a cada chamada dos métodos.

10 Respostas

ralphsilver

Cara não entendi muito onde você quer chegar, mas vamos lá.

Você está descartando a idéia de ter 2 tipos diferentes de conexao.

você precisa instancia o EntityManager sempre principalmente para especificar em qual persistenceUnit ele pertence, seja ele por annotacions

ou por retorno de classe estática

Realmente quando se trabalha com apenas um persistenceUnit essa solução é totalmente viável, mas e quando se trabalha com mais de um persistenceUnit?

Java_Player

No meu caso eu só trabalho com um PersistenceUnit. Mas de qualquer forma, nada impede que eu use singleton para mais de um persistenceUnit.

O principal motivo de eu estar fazendo este questionamento, é que se eu uso Singleton, a página inicial do meu site demora 5 segundos para carregar, enquanto que se eu instancio o entityManager a cada chamada de cada método, o tempo passa para 12 segundos, uma diferença muito grande, não?

Java_Player

Descobri que a diferença (de 4 segundos para 12 segundos) é por causa do cache que o JPA faz.

Na primeira vez que abrem a página inicial do meu site, demora uns 20 segundos para abrir. Mas depois, se eu estiver usando singleton, o tempo cai para 4 segundos, senão cai para 12 segundos.

Se eu instanciar o EntityManager a cada chamada de cada método service, eu estou jogando fora esse recurso de cache do JPA, não???

ralphsilver

Sim e eu concordo com você tanto que eu também uso um singleton para minhas aplicações.

Quando o projeto de empresa não me cobra tecnologia específica, eu instancio o entityManager nas minhas classes beans do EJB através da annotation @PersistenceContext pois é ele quem vai manter o controle das minhas transações. eu nem preciso instanciar essa classe para obter uma instancia dela… o próprio ejb observa e faz a inicialização… quando o programa ainda está fazendo deploy.

daí… para não haver problemas com instancias e me facilitar com Sessions eu faço da seguinte forma:

public static synchonized PessoaDAO getInstance(EntityManager em){ if(pessoaDAO == null){ pessoaDAO = new PessoaDAOImpl(); pessoaDAO.setEm(em); } return pessoaDAO; }

Enfim… na hora de fazer alguma ação… basta eu acessar essa classe estática para fazer ações com a classe PessoaDAO por exemplo.
Entendi onde quer chegar. E tenho certeza que muitas pessoas usam uma classe Singleton para isso. Até mesmo os frameworks que dão suporte ao JPA usam também uma mesma instancia para as ações com EntityManager.

O problema do próprio framework já ter uma classe dessas cai no mesmo problema que eu falei anteriormente… bom, mas pensando melhor… realmente… o JPA já poderia ter uma própria classe singleton EntityManager. Bastava apenas especificar no persistence.xml as classes pertencentes ao unitName.

A

No exemplo do nosso camigo Java Player, o entityManager e o entityManagerFactory não são fechados. Isso é correto?

dingouz

Java Player, sua idéia resolveu um problema de performance sinistro que eu estava tendo. Valeu!

esthercamilo

Singleton não deve ter um construtor private?

dingouz

Sim, para que se evite a criação de uma nova instância.

ralphsilver

Sim, para que se evite a criação de uma nova instância.

depende…

Se vc não quiser dar outra opção de modo de uso, a idéia é deixar o construtor private.

dingouz

Sim, para que se evite a criação de uma nova instância.

depende…

Se vc não quiser dar outra opção de modo de uso, a idéia é deixar o construtor private.

exato.

Criado 19 de outubro de 2008
Ultima resposta 25 de nov. de 2010
Respostas 10
Participantes 5