O que é Spring Data JPA?

Postado por em   ●   13 comentários

Gostaria de conhecer um framework que vai mudar (pra melhor) a forma como você implementa a camada de persistência de seus projetos Java?

Não importa se você trabalha com o conceito de DAO ou Repositório, a questão é que você pode ser muito mais produtivo na hora de programar sua camada de persistência se utilizar o Spring Data JPA.

Se você usa JPA, acredito que vai gostar bastante dele. Então continue aqui comigo para aprender mais sobre:

  • O que é o Spring Data JPA
  • Como usar o JPARepository e ser muito produtivo
  • Criar consultas sem escrevê-las, só pela assinatura do método (curioso isso, não acha?)
  • Utilizar JPQL através da anotação @Query

Vamos lá?

O que é Spring Data JPA?

O Spring Data JPA é um framework que nasceu para facilitar a criação dos nossos repositórios.

Ele faz isso nos liberando de ter que implementar as interfaces referentes aos nossos repositórios (ou DAOs), e também já deixando pré-implementado algumas funcionalidades como, por exemplo, de ordenação das consultas e de paginação de registros.

Ele (o Spring Data JPA) é, na verdade, um projeto dentro de um outro maior que é o Spring Data. O Spring Data tem por objetivo facilitar nosso trabalho com persistência de dados de uma forma geral. E além do Spring Data JPA, ele possui vários outros projetos:

  • Spring Data Commons
  • Spring Data Gemfire
  • Spring Data KeyValue
  • Spring Data LDAP
  • Spring Data MongoDB
  • Spring Data REST
  • Spring Data Redis
  • Spring Data for Apache Cassandra

…mas, provavelmente, o mais utilizado desses é o Spring Data JPA, que é o nosso assunto aqui.

Configurando o Spring Data JPA

A gente vai trabalhar aqui com o Spring Boot, e em projetos com ele o Spring Data JPA já vem configurado através de convenções. Essa é uma dobradinha muito boa porque, além de sermos produtivos em nossa camada de persistência, ficamos também na parte de configurações.

No final do artigo vou disponibilizar o código-fonte pra você, mas vou adiantar aqui o que é necessário criar para seguir com os exemplos que irei mostrar. Lembrando que é um projeto Maven.

Você vai precisar das seguintes dependências no pom.xml:

Ainda no pom.xml, é necessária a tag parent com referência ao Spring Boot:

Depois do pom.xml configurado, você vai precisar também de uma classe como a que está abaixo para poder iniciar a aplicação:

Para você ter uma pequena ideia de quanto a gente economizou com a configuração do JPA – sem falar nas outras coisas que também já ficam configuradas por tabela como segurança, templates, etc. -, você pode olhar o código-fonte de um artigo anterior, sobre Spring Security, onde eu utilizei JPA e não fiz o uso do Spring Boot.

Interface JPARepository

Você já chegou a fazer algum repositório (ou DAO) genérico com os métodos buscar, salvar (ou atualizar) e remover? Pois é, essa interface é mais ou menos isso.

Ela tem todos os métodos que a gente precisa para fazer um CRUD (criar, ler, atualizar, deletar). Nós vamos usá-la agora pra que você veja o quanto é simples.

Mas antes, vamos construir a nossa entidade:

É uma entidade bem simples mesmo porque o foco aqui é o Spring Data JPA.

Agora já podemos criar nosso repositório para a entidade Produto. Vamos chamá-lo de Produtos:

É só isso que precisamos para poder utilizá-lo!

O que!? Está esperando eu criar a implementação da interface Produtos? Não, não precisa.

Quer dizer, precisa sim, mas quem vai disponibilizar uma pra gente, em tempo de execução, é o próprio Spring Data JPA!

Legal, não é mesmo?

A partir de agora você pode utilizar o repositório da mesma forma que qualquer outro que já tenha criado.

Para observar o funcionamento disso, vou criar um controlador com Spring MVC. Vou chamá-lo de ProdutosResource. A ideia é trabalhar com uma requisição web devolvendo somente JSON. Isso é mais que suficiente para fazermos os testes do nosso repositório.

Agora basta fazermos requisições para o nosso controlador.

As requisições HTTP do tipo GET para os métodos buscar e pesquisar, você pode fazer em um navegador mesmo:

  • http://localhost:8080/produtos
  • http://localhost:8080/produtos/1

Para os meus testes, em particular, eu utilizei o Postman. Essa é uma extensão para o Google Chrome que nos ajuda, dentre outras coisas, a fazermos testes em nossos controladores. Assim posso testar, com facilidades, as requisições HTTP que são do tipo POST e DELETE.

Testando a API de produtos com o Postman

Se você vai utilizá-lo também, então pode baixar a coleção que criei – chamada “Artigo Spring Data JPA” – e importá-la no Postman através daquele botão Import no canto superior esquerdo. Dessa forma, vai ser só clicar no botão Send – em azul – para aquelas requisições que quiser testar.

Ordenação e paginação de registros

Além dos métodos CRUD, que ganhamos do Spring Data JPA, nós temos também os recursos de ordenação e paginação a nossa disposição.

Esses recursos estão presentes nas outras versões do método findAll. Primeiro vou mostrar a versão que faz a ordenação dos registros:

Na versão acima usamos o método que recebe o tipo Sort como parâmetro. Assim podemos receber da requisição a propriedade pela qual a consulta será ordenada e qual a direção (ascendente ou descendente).

Para testar essa nova versão, você pode fazer uma requisição para http://localhost:8080/produtos?ordenacao=nome&direcao=DESC. Pode usar tanto o Postman quanto o navegador.

Avançando mais um passo, temos a paginação também. Não é muito difícil implementar, mas é melhor ter pronto do que ter que fazer do zero, concorda?

Para paginação, usamos a versão do método findAll que recebe uma instância da interface Pageable – no caso, estamos passando uma instância da classe concreta PageRequest:

Repare que essa versão do método findAll não devolve uma coleção de registros, e sim uma instância da interface Page. O legal disso é que, além da lista de produtos requisitada, também já temos disponíveis as seguintes informações:

  • getNumber: o número da página
  • getSize: a quantidade de registros por página
  • getNumberOfElements: a quantidade de registros retornados (quase igual a getSize, mas pode mudar para o caso de ser a última página)
  • isFirst: se é a primeira página
  • isLast: se é a última página
  • hasNext: se tem próxima página
  • hasPrevious: se tem página anterior
  • getTotalPages: total de páginas
  • getTotalElements: total de registros

Repare também que estamos paginando e ordenando os registros. Para fazer mais esse teste você pode fazer uma requisição para http://localhost:8080/produtos?pagina=0&size=10.

Fazendo consultas com a assinatura do método

Até o momento vimos recursos do Spring Data JPA que são uma mão na roda. Porém o mais interessante desse framework é a criação de consultas a partir da assinatura do método.

Vamos a um exemplo básico. Nesse primeiro, iremos criar uma consulta que retorna o produto pelo nome.

Observando que também não precisamos dar uma implementação para esse método findByNome.

Repare que a nossa consulta começa com a palavra find. É preciso que seja com ela ou com:

  • read
  • get
  • query

Após a palavra find e antes de By, eu poderia ter colocado mais alguma. Por exemplo, eu podia ter usado findProdutoByNome. Nesse caso, penso eu, que não é necessário, mas poderá ter algum outro que seja interessante pra você.

Logo depois do primeiro By é onde começam as condições, equivalente ao where do JPQL.

Nesse primeiro caso, usei somente o nome da propriedade “nome”. Com isso, o Spring Data entendeu que ele deve buscar um produto que seja igual ao que for passado no primeiro parâmetro (que, por um acaso, se chama “nome” também).

Deixa eu te mostrar agora um exemplo com uma condição where mais explicita:

Esse muda duas coisas em relação ao anterior. Primeiro que ele está usando a condição StartingWith e outro que ele devolve uma lista de produtos.

Essa condição diz ao Spring Data para consultar por todos os produtos que começarem com a string passada no primeiro parâmetro. O próprio Spring Data JPA vai se encarregar de colocar o sinal de percentual.

Podemos ainda ordenar os registros assim:

Agora que expliquei como as assinaturas dos métodos devem ser estruturadas, vou deixar aqui mais alguns exemplos pra você:

Acredito que, seguindo os exemplos acima, dá para brincar bastante. :)

Utilizando JPQL através da anotação @Query

Acho o recurso, de criar consultas pela assinatura do método, incrível, mas ele não é bala de prata. Você, provavelmente, ainda vai precisar executar consultas com JPQL.

O time de desenvolvimento do Spring Data JPA, claro, sabia disso e incluíram a anotação @Query pra gente.

Veja como funciona:

Como você já deve imaginar, nós não precisamos dar a implementação para este método.

O que precisamos criar é a consulta. Repare ainda que essa consulta recebe um parâmetro. Por causa disso o nosso método também deve receber um parâmetro, pois, o Spring Data JPA usará ele na hora de executá-la.

Importante notar também que o nome pesquisarProdutos foi um nome aleatório. Ele não precisa seguir regra alguma, pois, a consulta que vale é a que está na anotação.

Conclusão

Vimos aqui sobre o que, mais exatamente, é o Spring Data JPA.

Aprendemos a utilizar a interface JPARepository e depois como definir consultas criando somente a assinatura do método dentro da interface.

Minha programação ficou consideravelmente mais ágil depois do Spring Data JPA. Pelo que viu aqui, acha que isso vai acontecer (ou já acontece) com você também? Deixe aí nos comentários.

Pra finalizar, você deve ter percebido que falamos bastante de Spring Boot, percebeu?

Caso você queira aprender mais sobre ele, então pode baixar nosso e-book Produtividade no Desenvolvimento de Aplicações Web Com Spring Boot:

Produtividade no desenvolvimento de aplicações web com Spring Boot.

No mais, um abraço pra você e até uma próxima!

PS: você pode baixar o código-fonte de exemplo em nosso GitHub: http://github.com/algaworks/artigo-spring-data-jpa

É graduado em Sistemas de Informação, trabalha como instrutor na AlgaWorks e está no mercado de programação Java há mais de 8 anos, principalmente no desenvolvimento de sistemas corporativos.

13 comentários sobre “O que é Spring Data JPA?

  1. Marcos Moura -

    Excelente Post, vocês são incríveis!

    Tenho uma duvida em relação ao comando do Banco de Dados innerjoin, pra realizar uma pesquisa contendo dados de 2 tabelas, como devemos proceder com jpa?

  2. Alexandre Afonso Autor do post-

    Valeu Marcos!

    Sobre sua dúvida, vamos imaginar a entidade Usuario e Grupo (grupos de usuário). Você poderia fazer algo como:

    select u from Usuario u join u.grupos g where g.nome = ‘ADMIN’

    E essa mesma consulta com Spring Data JPA (pela assinatura) seria:

    interface Usuarios extends JPARepository {
    List
    findByGrupoNome(String nome);
    }

    Abraço!

  3. Victor Rocha -

    Excelente post.
    Tenho uma dúvida, no caso da paginação, como ficaria no HTML? Suponhamos que eu tenha uma lista de produtos, e estou apresentando 10 produtos por página. Logo abaixo da lista eu tenho números de 1 a N, que são as páginas. Cada número vai fazer uma requisição GET referente a página equivalente?

  4. Alexandre Afonso Autor do post-

    Valeu Victor!

    No HTML você iria retornar assim:

    public ModelAndView pesquisar(…) {
    Page paginacao = produtos.findAll(new PageRequest(
    pagina, porPagina, new Sort(direcao, ordenacao)));

    ModelAndView mv = new ModelAndView(“produtos.html”);
    mv.addObject(“paginacao”, paginacao);

    return mv;
    }

    Assim você teria na sua página todos os atributos da interface Page que mencionei no artigo. Daí basta você montar os links de paginação (anterior, próximo, última página, primeira página, etc.)

    Abraço!

  5. Kleberson Santos -

    Lindo artigo Alexandre. Mas tenho uma dúvida quanto a busca de dados em banco legados. Vejo que o Spring Data JPA usa a própria Classe de Modelo para associar a uma entidade JPA. O que devo fazer quando os tipos de dados do sistema legado é diferente do modelo mapeado onde um EntityManager conectado a outro banco retorna registros que precisam ser convertidos.

  6. Alexandre Afonso Autor do post-

    Valeu Kleberson!

    Esse seu caso é bem específico. Difícil de falar porque eu não sei o quanto cada entidade está sendo utilizada. Uma resposta como essa precisaria que todas as premissas fossem postas a mesa.

    Mas o que eu faria era criar duas entidades. Uma para cada banco. Daí eu criaria um método na entidade legada que converteria para a entidade atualizada.

    Mas a melhor solução mesmo é pensar em ter somente uma tabela. Pegar os dados do banco legado, convertê-los e passar para o banco atualizado.

    Abraço!

  7. Joabe -

    Bom dia Alexandre,

    Seus artigos são ótimos mesmo cara, parabéns. Uma pergunta, você deu o nome da interface que criou de “Produtos”, temos que obrigatoriamente criar uma interface pra cada modelo correto? De genérico mesmo só a interface do spring-data-jpa pra estendermos?

    Obrigado!

  8. Alexandre Afonso Autor do post-

    Boa tarde Joabe!

    Quase. Isso porque talvez não precise para todos os casos. Se você tem duas entidades Pedido e ItemPedido, então talvez não precise criar um repositório de ItemPedido, pois, na maioria das vezes um ItemPedido não faz sentido fora do Pedido.

    Abraço!

  9. Ricardo -

    Olá, Alexandre. Parabéns pelo post. Tenho duas dúvidas:
    1º Para consultas mais elaboradas em que é preciso utilizar o SQL como no exemplo:
    Ex1.:–dateadd(dd, (prd.[RenewBeforeDay] * (-1)), ctr.[ExpiryDate]) as renewableDate.
    ou
    Ex2.: datediff(dd, isnull(eds.[ProposalDate], eds.[QuotationDate]), getdate()) <= pdv.[ValidityProposal]), 0) as pendencyIdShipping
    Poderia inserir essas consultas direto na assinatura do método ou teria que possuir uma classe de implementação pra este fim?, e pegando o gancho seria possível colocar essas todas as consultas (JPQL e SQL) em um arquivo property e ou xml (eX.: myquery.hbm.xml).

    2º Para criar consultas em criteria como faria nesse caso, ou somente JPQL?

  10. Alexandre Afonso Autor do post-

    Beleza Ricardo?

    Obrigado pelos parabéns!

    Vamos lá. Para a primeira pergunta. Você teria que fazer algo como:

    @Query(value = “…”, nativeQuery = true)
    List pesquisarProdutos(String nome);

    E também é possível colocar as consultas em um arquivo externo.

    Para segunda pergunta, se estiver falando do seus Ex1 e Ex2, então você teria que deixar como queries nativas. Ou fazer alguns cálculos através do próprio Java e depois montar a query.

    Abraço!

  11. Joathan -

    Parebens pelo ebook, assim como todos os conteúdos da algaworks são excelentes.

    Minha duvida é a seguinte: como implementar o @PutMapping(“/{id}”)?

  12. Alexandre Afonso Autor do post-

    Joathan, valeu pelos parabéns!

    Seguindo a ideia do artigo, seria exatamente a mesma coisa que com o PostMapping. Só que você vai trocar a anotação e vai trocar também o método HTTP usado no Postman.

    Abraço!

  13. Paulo Sérgio de Val -

    Galera quero tirar uma dúvida sobre critério

    Eu consigo fazer um critéria com uma entidade que não esteja mapeada em outra entidade? Ou tenho que usar query nativa para fazer essa consulta?

    Ex: tenho uma entidade usuario e outra produto mas não tenho. Relacionamento de produto com usuário mas tenho que trazer o nome da pessoa na query de produto sendo que na pessoa existe so uma variável preduto sem relacionamento.

Deixe um comentário