[RESOLVIDO] Performance JPA

11 respostas
Bambatera

Galera minha dúvida é a seguinte: Como faço para melhorar a performance de minha conexão JPA ao banco de dados ?
Explico, criei uma classe “genérica” para realizar o DAO do meu banco de dados, mas a conexão ao banco está demorando muito, cerca de 5 a 10 segundos.
Segue o código da classe:

import java.util.ArrayList;
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.EntityTransaction;
import javax.persistence.Query;
import org.apache.log4j.Logger;

/**
 *
 * @author Leandro de Menezes da Silva
 */
public class DAO<T> {

    private T pEntidade;
    private EntityManager pEntityManager;
    private EntityTransaction pEntityTransaction;

    /**
     * Construtor da classe. <p> Nota: A classe deve ser construída
     * obrigatoriamente com a passagem dos dois parâmetros.
     *
     * @param vNewEntidade Objeto representando a entidade a ser persistida no
     * banco de dados.
     * @param vNewEntityManager Objeto do tipo <tt>EntityManager</tt> contendo a
     * conexão estabelecida ao banco de dados.
     */
    public DAO(T vNewEntidade, EntityManager vNewEntityManager) {
        this.pEntidade = vNewEntidade;
        this.pEntityManager = vNewEntityManager;
    }

    /**
     * Método de persistência para inserção de registros no banco de dados.
     *
     * @return <tt>true</tt> caso o registro tenha sido inserido com sucesso,
     * <tt>false</tt> caso contrário.
     */
    public boolean insert() {
        boolean blnRet = false;
        if (pEntidade != null) {
            try {
                pEntityTransaction = pEntityManager.getTransaction();
                pEntityTransaction.begin();
                pEntityManager.persist(pEntidade);
                pEntityTransaction.commit();
                blnRet = true;
            } catch (Exception ex) {
                Logger log = Logger.getLogger(DAO.class);
                log.fatal("Erro ao inserir o registro!\n" + ex);
                pEntityTransaction.rollback();
            }
        }
        return blnRet;
    }

    /**
     * Método de persistência para atualização de registros no banco de dados.
     *
     * @return <tt>true</tt> caso o registro tenha sido inserido com sucesso,
     * <tt>false</tt> caso contrário.
     */
    public boolean update() {
        boolean blnRet = false;
        if (pEntidade != null) {
            try {
                pEntityTransaction = pEntityManager.getTransaction();
                pEntityTransaction.begin();
                pEntityManager.merge(pEntidade);
                pEntityTransaction.commit();
                blnRet = true;
            } catch (Exception ex) {
                Logger log = Logger.getLogger(DAO.class);
                log.fatal("Erro ao inserir o registro!\n" + ex);
                pEntityTransaction.rollback();
            }
        }
        return blnRet;
    }

    /**
     * Método de persistência para exclusão de registros no banco de dados.
     *
     * @return <tt>true</tt> caso o registro tenha sido inserido com sucesso,
     * <tt>false</tt> caso contrário.
     */
    public boolean delete() {
        boolean blnRet = false;
        if (pEntidade != null) {
            try {
                pEntityTransaction = pEntityManager.getTransaction();
                pEntityTransaction.begin();
                pEntityManager.remove(pEntidade);
                pEntityTransaction.commit();
                blnRet = true;
            } catch (Exception ex) {
                Logger log = Logger.getLogger(DAO.class);
                log.fatal("Erro ao inserir o registro!\n" + ex);
                System.out.println(ex.getMessage());
                ex.printStackTrace();
                pEntityTransaction.rollback();
            }
        }
        return blnRet;
    }

    /**
     * Método da persistência para seleção de registros no banco de dados.
     *
     * @param vstrQueryNamed Nome da Query a ser executada na persistência.
     * @return Lista da entidade passada como parâmetro na instanciação da
     * classe.
     */
    public List<T> select(String vstrQueryNamed) {
        List<T> plstObjeto = new ArrayList<>();
        try {
            Query qry = pEntityManager.createNamedQuery(vstrQueryNamed);
            plstObjeto = qry.getResultList();
        } catch (Exception ex) {
            Logger log = Logger.getLogger(DAO.class);
            log.fatal("Erro ao pesquisar o registro!\n" + ex);
        }
        return plstObjeto;
    }
}

Outro problema é com relação a atualização que chegou a demorar 1 minuto para atualizar 1 registro e exclusão de registros que não consegui realizar.
Estou usando Netbeans, Java Swing e PostgreSQL 9.2

Desde já agradeço a ajuda de todos.

11 Respostas

kadu.m.lino

A primeira coisa a se fazer aih é retirar o controle de transação do seu DAO, se possível a nível de request, vc vai ter menos dor de cabeça!

igor_ks

5 a 10 segundos em banco de dados local ou remoto?
Se for local é estranho essa demora…

Tem certeza que é na hora de fazer o commit() que ele demora esse tanto? Debugando seu codigo, ele demora esse tempo pra passar do pEntityTransacation.commit() para blnRet = true (no caso do metodo insert)?

Bambatera

Na realidade, o insert e o update já consegui resolver, porém, a exclusão não está funcionando, e, quando vou realizar a pesquisa está demorando muito, exatamente na linha 117 do código que postei, chega a levar 2 minutos, sendo que, na linha anterior leva 1 segundo e meio pra executar, agora não sei se é devido ao nº de registros.

kadu.m.lino

no caso da demora do resultado… vc pode fazer com que ele traga um limit, conforme o usuário for precisando

.setFirstResult(100) // vai pegar a partir do centésimo elemento da lista
.setMaxResults(100); //vai trazer 100 registros

assim vc busca os objetos conforme a necessidade do usuário, ao invés de mandar tudo de uma vez… agora se é pra gerar relatório vc terá que criar um índice no banco pra agilizar na busca

que erro está retornando no método delete?

Bambatera

Este é o erro que aparece no console quando tento executar o delete.

java.lang.IllegalArgumentException: Entity must be managed to call remove: ID = 1500005 , Descr. = TESTE: 500002, try merging the detached and try the remove again.
kadu.m.lino

Bambatera, tem certeza que esse ID existe no banco?

pq sua entidade não precisa estar gerenciada para ser excluida(se não me falha a memória)

kadu.m.lino

É isso msm (http://docs.jboss.org/hibernate/orm/3.5/api/org/hibernate/Session.html#delete(java.lang.Object))

delete

void delete(Object object)
throws HibernateException
Remove a persistent instance from the datastore. The argument may be an instance associated with the receiving Session [size=18][color=red]or a transient instance with an identifier associated with existing persistent state[/color][/size][color=red] [/color][color=blue] [/color]. This operation cascades to associated instances if the association is mapped with cascade=“delete”.

ou seja, não precisa estar gerenciada!

Bambatera

kadu, muito obrigado, era isso mesmo, corrigi aki e funcionou, veja como ficou o código:

public boolean delete(int id) throws Exception {
        boolean blnRet = false;
        if (pEntidade != null && id > -1) {
            T entidade = (T) pEntityManager.find(pEntidade.getClass(), id);
            pEntityTransaction = pEntityManager.getTransaction();
            pEntityTransaction.begin();
            pEntityManager.remove(entidade);
            pEntityTransaction.commit();
            blnRet = true;
        }
        return blnRet;
    }
kadu.m.lino

Bacana vc ter conseguido…

só uma dica!

quando vc tiver desenvolvendo tenta analisar o código e perguntar se aquela linha de código que vc está add está no lugar certo!

o ideal seria o seu método “delete” ter a responsabilidade de apenas deletar o obejto…

public void delete(int id) {  
        pEntityManager.remove(entidade);    
}

e delegar as outras linhas de código para camadas mais acima… deixaria seu código menos acoplado, de fácil na manutenção e mais entendível! rs

até mais!

ribclauport

kadu.m.lino veja que na verdade ele não está usando o método delete, ele está usando o metodo remove da especificação JPA!

Digo isso pois sua afirmação:

Não está em conformidade com a documentação, pois lembrando que transiente é diferente de detached, ou seja se uma entidade está detached ela não está gerenciada, e se você tentar deletar uma entidade detached vai receber um erro veja o que diz a documentação retirada de http://docs.oracle.com/javaee/5/api/javax/persistence/EntityManager.html#remove%28java.lang.Object%29

Veja que você vai receber uma exception se um objeto a ser deletado não for uma entidade ou se a entidade for detached!

É bom dar uma estudada no método merge() e também no método contains(), o primeiro atacha uma entidade desatachada, e o segundo verifica se aquela entidade faz parte do contexto de persistência…, apesar de ter resolvido o problema penso que é importante relatar o fato para o caso de futuras consultas a esse post, pois pode parecer que o método remove não lança uma exception para entidades não gerenciadas, logo uma entidade detached não está gerenciada, mas “já foi” gerenciada, e irá resultar em exception se for passada para remove.

att.

kadu.m.lino

Realmente, mal de hibernate! rs

vlw ribclauport

abrass

Criado 28 de dezembro de 2012
Ultima resposta 3 de jan. de 2013
Respostas 11
Participantes 4