JPA - EntityManager e Singleton

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.

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?

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?

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???

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.

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

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

Singleton não deve ter um construtor private?

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

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

depende…

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

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

depende…

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

exato.