Capítulo 3: Anotações Data e JPA
1. Anotações de Entidade
@Entity
Marca uma classe como entidade JPA (tabela no banco de dados).
@Entity
public class Product {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private BigDecimal price;
}
@Table
Personaliza o nome da tabela e suas restrições.
@Entity
@Table(
name = "products",
schema = "ecommerce",
uniqueConstraints = @UniqueConstraint(columnNames = {"sku"}),
indexes = @Index(name = "idx_product_name", columnList = "name")
)
public class Product {
// ...
}
@Id
Marca o campo como chave primária.
@Id
private Long id;
@GeneratedValue
Estratégia de geração da chave primária.
// Auto-incremento (PostgreSQL SERIAL, MySQL AUTO_INCREMENT)
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
// Sequência (recomendado para PostgreSQL)
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "product_seq")
@SequenceGenerator(name = "product_seq", sequenceName = "product_sequence", allocationSize = 1)
private Long id;
// UUID
@Id
@GeneratedValue(strategy = GenerationType.UUID)
private String id;
// O banco escolhe a estratégia
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
| Estratégia | Descrição | Banco típico |
|---|---|---|
IDENTITY | Auto-incremento | MySQL, PostgreSQL |
SEQUENCE | Sequência do banco | PostgreSQL, Oracle |
TABLE | Tabela de sequências | Todos |
UUID | Identificador UUID | Todos |
AUTO | Escolha automática | Todos |
@Column
Personaliza o mapeamento de uma coluna.
@Column(name = "product_name", nullable = false, length = 100)
private String name;
@Column(unique = true)
private String sku;
@Column(precision = 10, scale = 2)
private BigDecimal price;
@Column(columnDefinition = "TEXT")
private String description;
@Column(updatable = false) // Não pode ser modificado após a criação
private LocalDateTime createdAt;
@Column(insertable = false) // Não incluído nos INSERT
private LocalDateTime updatedAt;
@Enumerated
Mapeia um enum Java para o banco de dados.
public enum Role {
USER, ADMIN, MANAGER
}
@Entity
public class User {
@Enumerated(EnumType.STRING) // Armazena "USER", "ADMIN" (RECOMENDADO)
private Role role;
@Enumerated(EnumType.ORDINAL) // Armazena 0, 1, 2 (NÃO RECOMENDADO)
private Role roleOrdinal;
}
@Temporal
Especifica o tipo de data (apenas para java.util.Date, desnecessário com java.time).
@Temporal(TemporalType.DATE) // Apenas data
private Date birthDate;
@Temporal(TemporalType.TIMESTAMP) // Data + hora
private Date createdAt;
Com Java 8+, utilize LocalDate, LocalDateTime, Instant diretamente. @Temporal não é necessário.
@Lob
Indica um campo Large Object (BLOB/CLOB).
@Lob
private String longDescription; // CLOB (texto longo)
@Lob
private byte[] profileImage; // BLOB (binário)
@Transient
Exclui um campo da persistência (não cria coluna no banco).
@Entity
public class User {
private String firstName;
private String lastName;
@Transient
private String fullName; // Calculado, não armazenado no banco
public String getFullName() {
return firstName + " " + lastName;
}
}
2. Anotações de Relacionamento
@OneToOne
Relacionamento um-para-um.
@Entity
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
@OneToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
@JoinColumn(name = "address_id")
private Address address;
}
@Entity
public class Address {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String street;
private String city;
@OneToOne(mappedBy = "address")
private User user;
}
@OneToMany / @ManyToOne
Relacionamento um-para-muitos.
@Entity
public class Department {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
@OneToMany(mappedBy = "department", cascade = CascadeType.ALL, orphanRemoval = true)
private List<Employee> employees = new ArrayList<>();
}
@Entity
public class Employee {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "department_id")
private Department department;
}
@ManyToMany
Relacionamento muitos-para-muitos.
@Entity
public class Student {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
@ManyToMany
@JoinTable(
name = "student_course",
joinColumns = @JoinColumn(name = "student_id"),
inverseJoinColumns = @JoinColumn(name = "course_id")
)
private Set<Course> courses = new HashSet<>();
}
@Entity
public class Course {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String title;
@ManyToMany(mappedBy = "courses")
private Set<Student> students = new HashSet<>();
}
Resumo dos parâmetros de relacionamento
| Parâmetro | Descrição |
|---|---|
mappedBy | Lado inverso do relacionamento (sem coluna FK) |
cascade | Propagação das operações (PERSIST, MERGE, REMOVE, ALL) |
fetch | LAZY (carregamento tardio) ou EAGER (carregamento imediato) |
orphanRemoval | Remove órfãos automaticamente |
optional | O relacionamento pode ser null |
3. Anotações de Consulta
@Query
Define uma consulta JPQL ou SQL nativa personalizada.
public interface UserRepository extends JpaRepository<User, Long> {
// JPQL
@Query("SELECT u FROM User u WHERE u.email = :email")
Optional<User> findByEmail(@Param("email") String email);
// JPQL com JOIN
@Query("SELECT u FROM User u JOIN u.orders o WHERE o.total > :amount")
List<User> findUsersWithOrdersAbove(@Param("amount") BigDecimal amount);
// Consulta SQL nativa
@Query(value = "SELECT * FROM users WHERE created_at > :date", nativeQuery = true)
List<User> findRecentUsers(@Param("date") LocalDate date);
// Projeção (retorna parte dos dados)
@Query("SELECT new com.example.dto.UserSummary(u.id, u.name, u.email) FROM User u")
List<UserSummary> findAllSummaries();
}
@Param
Nomeia um parâmetro em uma consulta @Query.
@Query("SELECT u FROM User u WHERE u.name = :name AND u.role = :role")
List<User> findByNameAndRole(@Param("name") String name, @Param("role") Role role);
@Modifying
Indica uma consulta de modificação (UPDATE, DELETE).
@Modifying
@Transactional
@Query("UPDATE User u SET u.active = false WHERE u.lastLogin < :date")
int deactivateInactiveUsers(@Param("date") LocalDateTime date);
@Modifying
@Transactional
@Query("DELETE FROM User u WHERE u.active = false")
void deleteInactiveUsers();
@NamedQuery
Define uma consulta nomeada na entidade.
@Entity
@NamedQuery(name = "User.findActive", query = "SELECT u FROM User u WHERE u.active = true")
@NamedQuery(name = "User.countByRole", query = "SELECT COUNT(u) FROM User u WHERE u.role = :role")
public class User {
// ...
}
4. Anotações de Transação e Repository
@Transactional
Gerencia transações do banco de dados.
@Service
@Transactional(readOnly = true) // Por padrão somente leitura
public class OrderService {
public List<Order> findAll() {
return orderRepository.findAll(); // Transação somente leitura
}
@Transactional // Transação de escrita (sobrescreve readOnly)
public Order createOrder(OrderDto dto) {
Order order = new Order();
// ... lógica de criação
return orderRepository.save(order);
}
@Transactional(
propagation = Propagation.REQUIRED, // Usa a transação existente ou cria uma nova
isolation = Isolation.READ_COMMITTED, // Nível de isolamento
timeout = 30, // Timeout em segundos
rollbackFor = Exception.class // Rollback para qualquer exceção
)
public void processPayment(Long orderId) {
// Se uma exceção for lançada, tudo é revertido
}
}
| Parâmetro | Descrição |
|---|---|
readOnly | Otimização para leitura |
propagation | Comportamento da transação (REQUIRED, REQUIRES_NEW, etc.) |
isolation | Nível de isolamento (READ_COMMITTED, SERIALIZABLE, etc.) |
timeout | Duração máxima em segundos |
rollbackFor | Exceções que disparam rollback |
noRollbackFor | Exceções que NÃO disparam rollback |
@EnableJpaRepositories
Ativa os repositórios Spring Data JPA (geralmente auto-configurado pelo Spring Boot).
@Configuration
@EnableJpaRepositories(basePackages = "com.example.repository")
public class JpaConfig {
}
@EnableJpaAuditing
Ativa auditoria automática (datas de criação/modificação).
@Configuration
@EnableJpaAuditing
public class JpaAuditConfig {
}
@Entity
@EntityListeners(AuditingEntityListener.class)
public class Article {
@CreatedDate
@Column(updatable = false)
private LocalDateTime createdAt;
@LastModifiedDate
private LocalDateTime updatedAt;
@CreatedBy
@Column(updatable = false)
private String createdBy;
@LastModifiedBy
private String updatedBy;
}
5. Anotações de Herança JPA
@Inheritance
Estratégia de herança entre entidades.
// SINGLE_TABLE : todas as subclasses em uma única tabela (padrão)
@Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name = "type")
public abstract class Payment {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private BigDecimal amount;
}
@Entity
@DiscriminatorValue("CARD")
public class CardPayment extends Payment {
private String cardNumber;
}
@Entity
@DiscriminatorValue("PAYPAL")
public class PaypalPayment extends Payment {
private String paypalEmail;
}
| Estratégia | Descrição | Performance |
|---|---|---|
SINGLE_TABLE | Uma tabela para toda a hierarquia | Rápido (sem JOIN) |
TABLE_PER_CLASS | Uma tabela por subclasse | Médio |
JOINED | Tabela base + tabelas por subclasse com JOIN | Normalizado porém mais lento |
6. Anotações Específicas do Hibernate
@Formula
Coluna calculada no SQL (não existe fisicamente).
@Formula("(SELECT COUNT(*) FROM orders o WHERE o.user_id = id)")
private int orderCount;
@Where
Filtro SQL padrão em uma coleção.
@OneToMany(mappedBy = "user")
@Where(clause = "active = true")
private List<Order> activeOrders;
@BatchSize
Otimiza o carregamento de coleções (previne o problema N+1).
@OneToMany(mappedBy = "department")
@BatchSize(size = 20)
private List<Employee> employees;
Resumo Rápido
| Anotação | Papel |
|---|---|
@Entity | Classe = tabela no banco |
@Table | Configuração da tabela |
@Id | Chave primária |
@GeneratedValue | Geração automática do ID |
@Column | Configuração de coluna |
@Enumerated | Mapeamento de enum |
@OneToOne | Relacionamento 1:1 |
@OneToMany | Relacionamento 1:N |
@ManyToOne | Relacionamento N:1 |
@ManyToMany | Relacionamento N:N |
@JoinColumn | Coluna de junção (FK) |
@JoinTable | Tabela de junção |
@Query | Consulta personalizada |
@Modifying | Consulta UPDATE/DELETE |
@Transactional | Gerenciamento de transações |
@Transient | Campo não persistido |
➡️ Capítulo 4: Anotações Security, Teste e Avançadas