Blog Formação DEV

Utilizando JPQL para consultas em um banco de dados MySQL

Aprenda a fazer consultar customizáveis, performáticas e dinâmicas usando o JPQL.
Utilizando JPQL para consultas em um banco de dados MySQL
Texto de: Geraldo Daros

Introdução

Consultas aos bancos de dados são feitas diariamente em praticamente todos os softwares existentes, desde o site que você pesquisa por algum livro do seu autor preferido até o streaming de vídeo que você busca por seu gênero de filme favorito. Hoje veremos uma linguagem de consulta muito usada no Java e aprenderemos o necessário para fazermos nossas próprias consultas dinâmicas que atendem as necessidades do usuário.

O que é e para que usamos o JPQL?

Atualmente no ecossistema Java, é muito comum utilizarmos JPQL (Java Persistence Query Language) para fazer consultas. Essa é uma linguagem de consulta orientada a objetos usada para consultar dados em bancos de dados relacionais usando JPA (Java Persistence API). Neste artigo, exploraremos como usar JPQL para realizar consultas em um banco de dados MySQL, com muitos exemplos práticos que você pode usar no seu projeto.

Link para a documentação do JPQL.

Configurando projeto e criando a tabela de produtos

Aqui está o script SQL para criar a tabela de produtos no banco de dados MySQL:

CREATE DATABASE IF NOT EXISTS loja;
USE loja;

CREATE TABLE IF NOT EXISTS produto (
    id BIGINT AUTO_INCREMENT PRIMARY KEY,
    nome VARCHAR(255) NOT NULL,
    preco DECIMAL(10, 2) NOT NULL,
    quantidade INT NOT NULL
);

Isso criará um banco de dados chamado loja e uma tabela chamada produto com as colunas id, nome, preco e quantidade.

Configurando a entidade JPA

Agora, precisamos configurar uma entidade JPA que representará os dados da tabela de produtos. Aqui está uma classe Java que faz isso:

@Entity
@Table(name = "produtos")
public class Produto {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id")
    private Long id;

    @Column(name = "nome")
    private String nome;

    @Column(name = "preco")
    private Double preco;

    @Column(name = "quantidade")
    private Integer quantidade;

	// Getters e Setters
}

Certifique-se de que a configuração do seu banco de dados usando o JPA estejam corretas.

Consultando a tabela de produtos com JPQL

Uma vez que temos nossa tabela e entidade configuradas, podemos começar a fazer consultas usando uma consulta JPQL, ou query JPQL, que nada mais é que a tradução de consulta no contexto de solicitar informações do banco de dados. Agora, faremos uma pequena população no banco de dados com esses dados:

INSERT INTO produto (nome, preco, quantidade) VALUES
    ('Camiseta', 29.99, 100),
    ('Calça Jeans', 59.99, 50),
    ('Tênis', 79.99, 30),
    ('Bolsa', 39.99, 20),
    ('Relógio', 99.99, 15),
    ('Shorts', 19.99, 80),
    ('Chapéu', 9.99, 60),
    ('Meias', 5.99, 200),
    ('Sapato', 89.99, 25),
    ('Óculos de Sol', 49.99, 40);

Consultas simples

Primeiramente, criaremos uma consulta JPQL para buscar todos os produtos dessa forma:

SELECT p FROM Produto p

Ou dessa forma sem o alias:

SELECT Produto FROM Produto

No primeiro exemplo usamos um alias p para dar um nome para a nossa variável Produto, isso é comumente usado, mas não é obrigatório. Também usaremos esse alias em outras partes da consulta para referenciar a entidade.

Ambas essas consultas JPQL selecionarão todos os produtos.

Consultas com condições

Abaixo vemos uma consulta com filtro por preços abaixo de 10.

SELECT p FROM Produto p WHERE p.preco < 10

Na próxima consulta utilizamos o filtro para selecionar apenas com produtos que possuem “Cal” no nome, CONCAT(p.nome, '') com o uso do CONCAT estamos forçando que p.nome seja concatenado com uma string vazia, então mesmo que p.nome seja um número, após o CONCAT ele será uma string por ser concatenado com uma string vazia.

SELECT p FROM Produto p WHERE CONCAT(p.nome, '') LIKE '%Cal%’

Também podemos utilizar essa forma sem forçar a conversão para string:

SELECT p FROM Produto p WHERE p.nome LIKE '%Cal%'

No próximo exemplo, filtraremos com base no tamanho do campo nome.

SELECT p FROM Produto p WHERE LENGTH(p.nome) > 10

Consulta com Parâmetros

Até o momento fizemos apenas consultas hard-coded, com os valores inseridos manualmente, mas em projetos reais, quase tudo precisa ser dinâmico. Agora abordaremos o uso de parâmetros nas consultas.

SELECT p FROM Produto p WHERE p.preco < 10

Se transformaria em: 

SELECT p FROM Produto p WHERE p.preco < :nomeDaVariavel

nomeDaVariavel é o nome da variável que você quer usar na expressão. Basicamente quando colocamos dois pontos significa que o que virá a seguir é o nome de uma variável (parâmetro), o nome deverá ser usado para fazer a substituição depois. Segue exemplo usando sem Spring e depois com Spring:

Sem Spring:

String jpql = "SELECT p FROM Produto p WHERE p.preco > :valorLimite";
TypedQuery<Produto> query = entityManager.createQuery(jpql, Produto.class);
query.setParameter("valorLimite", variavelDesejada);

Com Spring:

@Query("SELECT p FROM Produto p WHERE p.preco > :valorLimite")
ArrayList<Produto> obterPorPrecoMenosQue(@Param("valorLimite") Double valorLimite);

Outro tipo de substituição de parâmetros é o uso do ?1, na expressão abaixo ?1? é um marcador de posição para um parâmetro de consulta em JPQL enquanto o número que o segue (1, neste caso), indica a ordem em que o parâmetro aparece na consulta. Isso é usado para vincular o parâmetro real à consulta quando você define o valor do parâmetro antes de executar a consulta. Exemplo:

Sem Spring:

String jpql = "SELECT p FROM Produto p WHERE p.preco > ?1";
Query query = entityManager.createQuery(jpql);
query.setParameter(1, variavelDesejada);

Com Spring:

@Query("SELECT p FROM Produto p WHERE p.preco > ?1")
ArrayList<Produto> obterPorPrecoMenosQue(Double valorLimite);

Basicamente a diferença de você usar o :variável para ?1 é que na primeira abordagem você poderá interpolar o nome do parâmetro na consulta e a outra forma será interpolada pela sequência dos parâmetros, podendo ser ?1, ?2, ?3, ?4..., isso depende da forma que você irá receber esses valores.

Consultas úteis

Aqui vai uma lista de algumas consultas úteis no seu dia a dia. Considere os exemplos apenas como base e use a sua entidade, lembrando, estamos usando a entidade Produto configurada anteriormente. O alias que foi inserido foi o p, porque é a inicial de Produto, o que é uma convenção popular. Faremos as consultas com valores hard-coded, mas caso você queira tornar essas consultas dinâmicas, basta adicionar um parâmetro no lugar dos valores comparados como foi mostrado anteriormente.

Ordem alfabética:

SELECT p FROM Produto p ORDER BY p.nome

Maior e menor preço:

SELECT p FROM Produto p WHERE p.preco = (SELECT MAX(p2.preco) FROM Produto p2)
SELECT p FROM Produto p WHERE p.preco = (SELECT MIN(p2.preco) FROM Produto p2)

Soma da quantidade de uma coluna:

SELECT SUM(p.quantidade) FROM Produto p

Preço entre 20.0 e 50.0:

SELECT p FROM Produto p WHERE p.preco BETWEEN 20.0 AND 50.0

Quantidade maior que 10 e ordenada de forma de decrescente, ou seja, na ordem alfabética, porém começando do Z e indo até A.

SELECT p FROM Produto p WHERE p.quantidade > 10 ORDER BY p.preco DESC

Maior valor por unidade:

SELECT p FROM Produto p ORDER BY (p.preco / p.quantidade) DESC

Menor valor total em estoque:

SELECT p FROM Produto p ORDER BY (p.preco * p.quantidade)

Preço maior que a média de preço entre todos os produtos:

SELECT p FROM Produto p WHERE p.preco > (SELECT AVG(p2.preco) FROM Produto p2)

Produtos com nomes que contêm mais de 10 caracteres com uma quantidade superior a 5:

SELECT p FROM Produto p WHERE LENGTH(p.nome) > 10 AND p.quantidade > 5

Produtos cujo nome deve estar incluso no conjunto 'Camiseta', 'Calça Jeans', 'Tênis'.

SELECT p FROM Produto p WHERE p.nome IN ('Camiseta', 'Calça Jeans', 'Tênis')

Acredito que com esses exemplos vocês poderão sair fazendo as próprias consultas de diversas formas diferentes.

Funções úteis do SQL

Aqui deixarei uma lista das funções SQL que temos disponíveis no JPQL com exemplos práticos.

ABS (valor absoluto do preço):

SELECT p FROM Produto p WHERE ABS(p.preco - 50.0) > 10.0

COALESCE (retorna o preço se for menor que 20, o COALESCE verifica uma lista de argumentos separados por vírgula (argumento1, argumento2, argumento3) e irá retornar o primeiro elemento que ele encontrar não nulo, então caso o p.preco for nulo ele retornará 0.0 para fazer a comparação com 20.0):

SELECT p FROM Produto p WHERE COALESCE(p.preco, 0.0) < 20.0

CONCAT (concatena valores):

SELECT CONCAT(p.nome, ' - ', p.quantidade) FROM Produto p

LENGTH (comprimento):

SELECT p FROM Produto p WHERE LENGTH(p.nome) > 10

UPPER (transforma as letras em maiúsculas):

SELECT UPPER(p.nome) FROM Produto p

LOWER (transforma as letras em minúsculas):

SELECT p FROM Produto p WHERE LOWER(p.nome) = 'tenis'

MOD (retorna o resto de uma divisão, como o famoso % que usamos em muitas linguagens de programação):

SELECT p FROM Produto p WHERE MOD(p.quantidade, 5) = 0

NULLIF (função NULLIF aceita dois argumentos e retorna null se os dois argumentos forem iguais; caso contrário, retorna o primeiro argumento. Neste caso, estamos comparando o campo preco de Produto com 0.0. Se o preço for igual a zero ou for nulo, NULLIF retornará null, o que é uma maneira de verificar se essa condição foi atendida ou não, ou seja, buscaremos somente os produtos com o preço null ou 0.0):

SELECT p FROM Produto p WHERE NULLIF(p.preco, 0.0) IS NULL

SQRT (raiz quadrada):

SELECT p FROM Produto p WHERE SQRT(p.preco) > 8.0

SUBSTRING (recebe 3 parâmetros: o primeiro é uma String e os próximos dois parâmetros representam o início e o fim da substring. Isso significa que a expressão abaixo pegará todos p.nome da primeira letra até a terceira letra. OBS: JPQL considera o índice 1 como o nosso índice 0 no Java, então a letra número 1 é realmente a primeira da String.):

SELECT SUBSTRING(p.nome, 1, 3) FROM Produto p

TRIM (remove espaços em branco):

SELECT TRIM(p.nome) FROM Produto p WHERE TRIM(TRAILING FROM p.nome) LIKE '%produto'

CASE (definindo uma expressão CASE, semelhante ao switch case):

SELECT CASE p.nome WHEN 'Camiseta' THEN 'Roupa' WHEN 'Tênis' THEN 'Calçado' ELSE 'Outro' END FROM Produto p

Há mais diversas outras funções e formas de fazer consultas. De forma geral abordamos os elementos que você deve ter domínio para conseguir criar suas próprias consultas.

Conclusão

JPQL é uma ferramenta poderosa para consultar dados em bancos de dados relacionais usando JPA e neste artigo, exploramos como usá-la para realizar consultas em um banco de dados MySQL. Executamos diversos tipos de consultas usando JPQL, incluindo consultas simples, consultas com parâmetros e consultas com ordenação. Espero que este artigo tenha fornecido uma introdução útil ao seu uso.

Sobre o autor
Cod3r

Cod3r

Com mais de 400 mil alunos, a Cod3r é uma das principais escolas de tecnologia do País. Um de seus produtos mais importantes é a Formação DEV, com objetivo de preparar os profissionais para o mercado.

Ótimo! Inscreveu-se com sucesso.

Bem-vindo de volta! Registou-se com sucesso.

Assinou com sucesso o Blog Formação DEV .

Sucesso! Verifique o seu e-mail para obter o link mágico para se inscrever.

As suas informações de pagamento foram atualizadas.

Seu pagamento não foi atualizado.