Com este post gostaria de compartilhar um pouco do conhecimento que adquiri ao trabalhar com JPA, são algumas dicas que, por mais simples que possam parecer ajudaram na resolução de problemáticas comuns.
Dica 1 – Connection Pool
Usar o pool de conexões embutido com o Hibernate é um erro que acontece com frequência, que pode gerar connections leaks. A configuração “hibernate.connection.pool_size” não é recomendada pela documentação para o uso em produção.
Existem varias opções de pools que podemos utilizar, mas uma excelente opção é o c3p0 e o melhor é que o Hibernate já vem com ele embutido.
Basta adicionar essas 4 linhas nas propriedades do hibernate e puff, temos uma considerável melhora na re-utilização das conexões, não gerando connections leak e matando conexões que não são mais utilizadas.
hibernate.c3p0.min_size=5
hibernate.c3p0.max_size=20
hibernate.c3p0.timeout=1800
hibernate.c3p0.max_statements=50
A configuração acima define:
Uma outra forma de configurar o c3p0 seria através de um datasource no servidor de aplicação com as configurações adicionais do c3p0.
Dica 2 – Não retornar desnecessariamente uma entidade
Por muitas vezes percebi que ao fazer um select com JPQL eu retornava a entidade quando precisava apenas do ID da mesma, depois de um tempo percebi que isso prejudica sem necessidade o desempenho da aplicação uma vez que todos os relacionamentos EAGERs são executados e retornados junto a entidade.
Dado uma entidade Carro, vamos a um exemplo JPQL retornando a entidade:
SELECT c FROM Carro c
Sendo que poderia ser apenas:
SELECT c.id FROM Carro c
Dica 3 – Controle do Lazy
Em alguns casos é melhor executar uma única query e ter um retorno mais completo do que cair no velho problema do n+1.
De que se trata o n+1? Se um Carrinho de Compras possui muitos Itens, e essa coleção é lazy, gastaremos duas queries para buscar o Carrinho de Compras e seus respectivos Itens. Mas se temos uma lista de Carrinhos de Compras resultante de uma query, para cada Carrinho de Compras teremos uma nova query executada para todo getItens invocados. 1 query para listar Carrinho de Compras, N queries para pegar os relacionamentos.
Para casos como esse uma saída mais eficiente que alterar o relacionamento para EAGER é fazer um JOIN FETCH, o que faz com que o objeto ou a lista de objetos retornados pela query já contenha em seu corpo a coleção desejada.
select c from CarrinhoDeCompras c left join FETCH c.itens i where…
Espera aí, mas isso é melhor que deixar o relacionamento lazy? Para cada caso é um caso, as vezes essa maneira atende o requisito da funcionalidade sem necessariamente alterar o mapeamento da entidade.
Espero que estas 3 dicas possam ajudar, no próximo post pretendo tratar sobre Query Cache, Second Cache Level e Open Session in View.