Durante o artigo serão explicados todos os meios de consulta disponíveis na implementação de referência do JPA. Abordaremos consultas nativas, JPQL, consultas nomeadas e a Criteria API, sempre com dicas de desempenho e de quando usar.
Em que situação o tema é útil:
É sabido que a grande maioria das aplicações tem como requisito não-funcional armazenar dados, e se esses dados são armazenados, precisamos de mecanismos eficientes para recuperá-los. É justamente neste contexto que o artigo trabalha.
Resumo DevMan:
Atualmente existem diversas maneiras de se consultar dados armazenados em um banco de dados. Sendo assim, é altamente recomendado conhecer esses meios e saber em qual situação empregá-los. Com base nesta necessidade, o artigo exibe não só as formas de consulta, mas também apresenta dicas para auxiliar na escolha da opção mais adequada.
É sabido que as aplicações, em sua grande maioria, têm como requisito não-funcional armazenar dados. Esse armazenamento é usualmente realizado pelos Sistemas Gerenciadores de Banco de Dados (SGBD), que, por sua vez, se comunicam com a aplicação em um nível mais baixo, trabalhando com as conexões do banco de dados por meio da manipulação de sockets. É nesse ponto que empregamos o Hibernate, abstraindo toda a comunicação de baixo nível entre a aplicação e o banco, fornecendo ainda uma excelente interface para consultas aos dados armazenados.
A experiência do autor tem mostrado que efetuar consultas em bancos de dados é a ação mais executada em sistemas. Levando em consideração esse fato, é importante conhecer as opções disponíveis para se recuperar informações previamente salvas. Com esse conhecimento em mãos, os desenvolvedores terão diferentes abordagens para solucionar seus problemas.
Neste contexto, este artigo apresentará os meios de se recuperar o que foi gravado em banco de dados usando o Hibernate. Esses meios foram criados para suprir algumas necessidades e serão explicados e exemplificados para um melhor entendimento do propósito de cada forma de se recuperar os dados armazenados.
Para começar, serão explicados alguns conceitos básicos relacionados a banco de dados. Em seguida, será apresentada uma aplicação que servirá de exemplo para os estudos de caso do artigo. Posteriormente, serão exibidos os meios disponíveis para recuperar as entidades no banco de dados.
Conceitos básicos
Neste tópico será relembrado de forma simples o que é um Sistema Gerenciador de Banco de Dados (SGBD), Object-Relational Mapping (ORM), chave primária, chave estrangeira e álgebra relacional. O leitor pode avançar para o próximo tópico caso já domine esses assuntos.
SGBD (Sistema Gerenciador de Bando de Dados)
Um Sistema Gerenciador de Banco de Dados é um software que gerencia toda a burocracia relacionada aos dados que uma aplicação precisa manter, como por exemplo, concorrência, dead-lock, quem tem permissão para executar tal comando e principalmente meios de organizar, armazenar e consultar dados. Esses sistemas são comumente chamados de bancos de dados ou SGBDs.
Entre outros, bancos de dados podem ser orientados a objetos, orientados a documentos ou relacionais. Para este artigo trabalharemos com bancos de dados relacionais. Esse será mais bem exemplificado no próximo subtópico.
ORM (Object-Relational Mapping)
É sabido que o tipo de banco de dados mais utilizado é o relacional. O autor desconhece pesquisas a cerca do assunto, mas não é preciso ir muito longe para provar isso. Basta olhar para todas as aplicações que o leitor já trabalhou e verificar quantas delas usavam banco de dados relacional. Provavelmente a maioria, se não forem todas, correto?
Um SGBD relacional (também conhecido como Relational Database Management System – RDBMS) é um banco que armazena dados que se relacionam (ou não) entre si. O problema disso é que quando trabalhamos com linguagens orientadas a objetos, supostamente precisaríamos de um sistema que além de armazenar dados, também armazenasse operações.
Apresentado o problema, podemos avançar explicando o que é Object-Relational Mapping ou, em tradução livre, Mapeamento Objeto-Relacional, que significa resolver o problema citado no parágrafo anterior, ou seja, salvar os atributos (sejam eles de valor ou de relação) de um objeto em um banco de dados relacional, ao passo que mantém as operações no próprio objeto.
Apenas para exemplificar, a Listagem 1 contém a definição de uma classe a partir da qual objetos são gerados.
Listagem 1. Código da classe Pessoa.
public class Pessoa {
private Integer id;
private String nome;
private Integer idade;
public String getDescricao() {
String descricao = “Identificação: “ + id.toString() + “\n”
“Nome: “ + nome + “\n”
“Idade: “ + idade.toString();
return descricao;
}
// getters e setters omitidos...
}
Veja agora, na Listagem 2, a representação desse objeto em um banco de dados relacional.
Listagem 2. Representação dos dados do objeto pessoa em um banco de dados relacional.
mysql> select * from pessoa;
+----+----------------+-------+
| id | nome | idade |
+----+----------------+-------+
| 1 | Pedro da Silva | 22 |
+----+----------------+-------+
Repare que apenas os valores dos atributos do objeto gerado a partir da classe Pessoa estão gravados no banco de dados. Sendo assim, uma ferramenta ORM ajuda a fazer a ligação entre os atributos dos objetos salvos em banco de dados e as operações dos objetos que estão em memória.
Além do problema clássico citado aqui, frameworks ORM costumam ter mais atribuições. Essas não serão abordadas no artigo, por não fazerem parte do escopo do mesmo, porém o leitor não terá problemas ao procurar por mais conhecimento em edições anteriores da Java Magazine.
Chave Primária e Chave Estrangeira
Para que uma entidade salva em banco de dados possa ser recuperada, é necessário que exista uma maneira única de identificá-la. Para tanto, geralmente é reservado um campo da tabela para essa função, e esse campo é comumente chamado de id ou codigo. Em alguns casos as entidades possuem chave primária em sua essência, tal como uma pessoa, que possui um RG e um CPF.
Esse campo deve conter um valor único para cada linha da tabela, caso contrário, dado um valor de uma chave primária, seriam resgatadas uma ou mais entidades e esse não é o efeito esperado. Essa chave pode ainda ser composta por mais de um campo da tabela.
A Listagem 3 exibe uma consulta SQL onde dado o valor 1, da chave primária id, uma única linha da tabela pessoa é retornada.
Listagem 3. Resgatando a entidade pessoa a partir de sua chave primária.
mysql> select * from pessoa where id = 1;
+----+----------------+-------+
| id | nome | idade |
+----+----------------+-------+
| 1 | Pedro da Silva | 22 |
+----+----------------+-------+
...