Capítulo 5: Introdução aos Repositories Spring Data JPA
Introdução
Agora que você domina os fundamentos do Spring Boot (estrutura, configuração, anotações), é hora de aprender a persistir dados em um banco de dados. O Spring Data JPA simplifica muito essa tarefa, permitindo que você interaja com o banco de dados sem escrever código SQL.
Objetivos do Capítulo
Ao final deste capítulo, você será capaz de:
- Entender o papel de um Repository Spring Data JPA
- Utilizar os 4 métodos básicos para CRUD
- Criar métodos de busca simples com convenções de nomenclatura
- Compreender como o Spring gera automaticamente as queries
O que é um Repository?
Definição
Um Repository é uma interface que permite interagir com o banco de dados sem escrever código SQL. O Spring Data JPA gera automaticamente a implementação.
Analogia: Um repository é como um bibliotecário que gerencia seus livros (dados) para você.
Arquitetura Completa
Responsabilidades:
| Camada | Papel | Exemplo |
|---|---|---|
| Controller | Gerencia as requisições HTTP | @RestController |
| Service | Lógica de negócio | UserService |
| Repository | Acesso a dados | UserRepository |
| Database | Armazenamento | PostgreSQL, H2 |
Criando uma Entidade Simples
Exemplo: Entidade User
Antes de criar um repository, precisamos de uma entidade - uma classe Java que representa uma tabela no banco de dados.
package com.example.demo.model;
import jakarta.persistence.*;
@Entity
@Table(name = "users")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private String email;
private int age;
// Construtores
public User() {
}
public User(String name, String email, int age) {
this.name = name;
this.email = email;
this.age = age;
}
// Getters e Setters
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
Anotações Essenciais
| Anotação | Papel | Exemplo |
|---|---|---|
@Entity | Marca a classe como entidade JPA | Cria uma tabela |
@Table | Especifica o nome da tabela | name = "users" |
@Id | Identifica a chave primária | Campo id |
@GeneratedValue | Geração automática do ID | Auto-incremento |
Os 4 Métodos Básicos
Interface JpaRepository
O Spring Data JPA fornece a interface JpaRepository que já contém todos os métodos CRUD básicos.
package com.example.demo.repository;
import com.example.demo.model.User;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface UserRepository extends JpaRepository<User, Long> {
// Não é necessário escrever código!
// Os métodos são herdados automaticamente
}
Explicação:
JpaRepository<User, Long>:User: Tipo da entidadeLong: Tipo do ID
Métodos Herdados Automaticamente
Aqui estão os 4 métodos essenciais que você pode usar imediatamente:
1. findById() - Buscar por ID
Assinatura:
Optional<User> findById(Long id)
Uso:
@Service
public class UserService {
@Autowired
private UserRepository userRepository;
public User getUserById(Long id) {
return userRepository.findById(id)
.orElseThrow(() -> new RuntimeException("User not found"));
}
}
SQL gerado:
SELECT * FROM users WHERE id = ?
2. findAll() - Buscar todos
Assinatura:
List<User> findAll()
Uso:
public List<User> getAllUsers() {
return userRepository.findAll();
}
SQL gerado:
SELECT * FROM users
3. save() - Criar ou Atualizar
Assinatura:
User save(User user)
Uso (Criação):
public User createUser(User user) {
return userRepository.save(user);
}
SQL gerado (se ID for null):
INSERT INTO users (name, email, age) VALUES (?, ?, ?)
SQL gerado (se ID existir):
UPDATE users SET name = ?, email = ?, age = ? WHERE id = ?
4. deleteById() - Remover por ID
Assinatura:
void deleteById(Long id)
Uso:
public void deleteUser(Long id) {
userRepository.deleteById(id);
}
SQL gerado:
DELETE FROM users WHERE id = ?
Tabela Resumo
| Método | Ação | Parâmetro | Retorno | SQL |
|---|---|---|---|---|
findById(id) | Ler um | ID | Optional<User> | SELECT ... WHERE id = ? |
findAll() | Ler todos | Nenhum | List<User> | SELECT * |
save(user) | Criar/Atualizar | Entidade | User | INSERT ou UPDATE |
deleteById(id) | Remover | ID | void | DELETE ... WHERE id = ? |
Convenções de Nomenclatura: As 3 Bases
Princípio Geral
O Spring Data JPA pode gerar automaticamente métodos de busca baseados no nome do método.
Formato:
findBy[Atributo]
1. findBy (Busca Simples)
Sintaxe:
findBy + NomeAtributo
Exemplos:
@Repository
public interface UserRepository extends JpaRepository<User, Long> {
// Busca por nome
User findByName(String name);
// Busca por email
User findByEmail(String email);
// Busca por idade
List<User> findByAge(int age);
}
SQL gerado:
| Método | SQL |
|---|---|
findByName("John") | SELECT * FROM users WHERE name = 'John' |
findByEmail("john@example.com") | SELECT * FROM users WHERE email = 'john@example.com' |
findByAge(25) | SELECT * FROM users WHERE age = 25 |
2. And (Combinar dois critérios)
Sintaxe:
findBy + Atributo1 + And + Atributo2
Exemplos:
@Repository
public interface UserRepository extends JpaRepository<User, Long> {
// Busca por nome E idade
List<User> findByNameAndAge(String name, int age);
// Busca por email E idade
User findByEmailAndAge(String email, int age);
}
SQL gerado:
| Método | SQL |
|---|---|
findByNameAndAge("John", 25) | SELECT * FROM users WHERE name = 'John' AND age = 25 |
findByEmailAndAge("john@example.com", 25) | SELECT * FROM users WHERE email = 'john@example.com' AND age = 25 |
3. Or (Critério alternativo)
Sintaxe:
findBy + Atributo1 + Or + Atributo2
Exemplos:
@Repository
public interface UserRepository extends JpaRepository<User, Long> {
// Busca por nome OU email
List<User> findByNameOrEmail(String name, String email);
// Busca por idade 20 OU 30
List<User> findByAgeOrAge(int age1, int age2);
}
SQL gerado:
| Método | SQL |
|---|---|
findByNameOrEmail("John", "john@example.com") | SELECT * FROM users WHERE name = 'John' OR email = 'john@example.com' |
Exemplo Completo: Arquitetura em 3 Camadas
1. Entidade (Model)
@Entity
@Table(name = "users")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private String email;
private int age;
// Construtores, Getters, Setters
}
2. Repository
@Repository
public interface UserRepository extends JpaRepository<User, Long> {
// Métodos herdados automaticamente:
// - findById(Long id)
// - findAll()
// - save(User user)
// - deleteById(Long id)
// Métodos customizados:
User findByEmail(String email);
List<User> findByAge(int age);
List<User> findByNameAndAge(String name, int age);
}
3. Service
@Service
public class UserService {
private final UserRepository userRepository;
public UserService(UserRepository userRepository) {
this.userRepository = userRepository;
}
// CREATE
public User createUser(User user) {
return userRepository.save(user);
}
// READ - todos
public List<User> getAllUsers() {
return userRepository.findAll();
}
// READ - por ID
public User getUserById(Long id) {
return userRepository.findById(id)
.orElseThrow(() -> new RuntimeException("User not found with id: " + id));
}
// READ - por email
public User getUserByEmail(String email) {
return userRepository.findByEmail(email);
}
// READ - por idade
public List<User> getUsersByAge(int age) {
return userRepository.findByAge(age);
}
// UPDATE
public User updateUser(Long id, User userDetails) {
User user = getUserById(id);
user.setName(userDetails.getName());
user.setEmail(userDetails.getEmail());
user.setAge(userDetails.getAge());
return userRepository.save(user);
}
// DELETE
public void deleteUser(Long id) {
userRepository.deleteById(id);
}
}
4. Controller
@RestController
@RequestMapping("/api/users")
public class UserController {
private final UserService userService;
public UserController(UserService userService) {
this.userService = userService;
}
// POST /api/users
@PostMapping
public User createUser(@RequestBody User user) {
return userService.createUser(user);
}
// GET /api/users
@GetMapping
public List<User> getAllUsers() {
return userService.getAllUsers();
}
// GET /api/users/123
@GetMapping("/{id}")
public User getUserById(@PathVariable Long id) {
return userService.getUserById(id);
}
// GET /api/users/email/john@example.com
@GetMapping("/email/{email}")
public User getUserByEmail(@PathVariable String email) {
return userService.getUserByEmail(email);
}
// GET /api/users/age/25
@GetMapping("/age/{age}")
public List<User> getUsersByAge(@PathVariable int age) {
return userService.getUsersByAge(age);
}
// PUT /api/users/123
@PutMapping("/{id}")
public User updateUser(@PathVariable Long id, @RequestBody User user) {
return userService.updateUser(id, user);
}
// DELETE /api/users/123
@DeleteMapping("/{id}")
public void deleteUser(@PathVariable Long id) {
userService.deleteUser(id);
}
}
Configuração H2 para Testes
application.yml
spring:
datasource:
url: jdbc:h2:mem:testdb
driver-class-name: org.h2.Driver
username: sa
password:
h2:
console:
enabled: true
path: /h2-console
jpa:
hibernate:
ddl-auto: create-drop
show-sql: true
properties:
hibernate:
format_sql: true
Acesso ao console H2:
http://localhost:8080/h2-console
Exercícios Práticos
Exercício 1: Repository Básico
Objetivo: Criar um repository simples
Instruções:
- Crie uma entidade
Product:Long idString nameDouble priceint quantity
- Crie
ProductRepositoryque estendeJpaRepository - Teste os 4 métodos básicos
Perguntas:
- Qual método usar para criar um produto?
- Como recuperar todos os produtos?
- Como remover um produto pelo seu ID?
Exercício 2: Métodos de Busca
Objetivo: Usar convenções de nomenclatura
Instruções:
- No
ProductRepository, adicione:- Busca por nome
- Busca por preço
- Busca por nome E preço
- Crie um serviço
ProductService - Teste em um controller
Perguntas:
- Qual SQL é gerado para
findByName? - Como buscar produtos de um determinado preço?
Exercício 3: Serviço Completo
Objetivo: Criar uma arquitetura completa
Instruções:
- Crie uma entidade
Student:Long idString firstNameString lastNameString emailint grade
- Crie
StudentRepositorycom:- Busca por email
- Busca por grade
- Busca por firstName e lastName
- Crie
StudentServicecom todas as operações CRUD - Crie
StudentControllercom todos os endpoints
Perguntas de Revisão
-
O que é um Repository no Spring Data JPA?
-
Quais são os 4 métodos herdados automaticamente do JpaRepository?
-
Qual a diferença entre
save()para criação e para atualização? -
Como o Spring sabe qual query SQL gerar para
findByName? -
Qual a diferença entre
AndeOrnos nomes dos métodos? -
Por que usamos
Optional<User>parafindById()? -
O que acontece se chamarmos
findById()com um ID que não existe? -
É possível combinar mais de 2 critérios com
And? Dê um exemplo.
Resumo do Capítulo
Pontos-Chave
- Um Repository é uma interface para acesso a dados
JpaRepositoryfornece 4 métodos básicos:findById,findAll,save,deleteById- As convenções de nomenclatura permitem criar métodos automaticamente
- 3 palavras-chave essenciais:
findBy,And,Or - O Spring gera o SQL automaticamente com base no nome do método
- Arquitetura: Controller → Service → Repository → Database
O que Você Sabe Agora
✅ Criar uma entidade JPA
✅ Criar um repository Spring Data JPA
✅ Utilizar os 4 métodos CRUD básicos
✅ Criar métodos de busca simples (findBy, And, Or)
✅ Construir uma arquitetura completa em 3 camadas
O que Você Vai Aprender Depois (Módulo 6)
🔜 Convenções de nomenclatura avançadas (15+ palavras-chave)
🔜 Joins entre entidades
🔜 Queries JPQL customizadas
🔜 Performance e otimização
🔜 Transações
Boas Práticas
DO (O que Fazer)
✅ Usar injeção por construtor para os repositories
✅ Nomear os métodos conforme as convenções do Spring Data JPA
✅ Tratar os casos em que findById() não encontra nada com Optional
✅ Separar a lógica de negócio (Service) do acesso a dados (Repository)
DON'T (O que Evitar)
❌ Colocar lógica de negócio nos repositories
❌ Chamar o repository diretamente do controller
❌ Ignorar o Optional retornado por findById()
❌ Criar nomes de métodos que não seguem as convenções
Próximos Passos
Praticar
Agora que você conhece os fundamentos dos repositories, é hora de praticar!
Vá para os TPs do Módulo 2:
- TP2.2: Banco de Dados H2 - Use H2 e os 4 métodos básicos
Para ir além (próximos módulos):
- Módulo 3: TP3.1: Arquitetura CRUD - Aplicação CRUD completa com validação
- Módulo 4: TP4.1: PostgreSQL - Migração para PostgreSQL em produção
Para se Aprofundar
Interessado em queries mais avançadas? Veja:
Módulo 6: Spring Data JPA Avançado (em breve)
- 15+ palavras-chave de busca
- Joins entre tabelas
- JPQL e queries customizadas
- Otimização de performance