Pular para o conteúdo principal

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égiaDescriçãoBanco típico
IDENTITYAuto-incrementoMySQL, PostgreSQL
SEQUENCESequência do bancoPostgreSQL, Oracle
TABLETabela de sequênciasTodos
UUIDIdentificador UUIDTodos
AUTOEscolha automáticaTodos

@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;
dica

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âmetroDescrição
mappedByLado inverso do relacionamento (sem coluna FK)
cascadePropagação das operações (PERSIST, MERGE, REMOVE, ALL)
fetchLAZY (carregamento tardio) ou EAGER (carregamento imediato)
orphanRemovalRemove órfãos automaticamente
optionalO 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âmetroDescrição
readOnlyOtimização para leitura
propagationComportamento da transação (REQUIRED, REQUIRES_NEW, etc.)
isolationNível de isolamento (READ_COMMITTED, SERIALIZABLE, etc.)
timeoutDuração máxima em segundos
rollbackForExceções que disparam rollback
noRollbackForExceçõ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égiaDescriçãoPerformance
SINGLE_TABLEUma tabela para toda a hierarquiaRápido (sem JOIN)
TABLE_PER_CLASSUma tabela por subclasseMédio
JOINEDTabela base + tabelas por subclasse com JOINNormalizado 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çãoPapel
@EntityClasse = tabela no banco
@TableConfiguração da tabela
@IdChave primária
@GeneratedValueGeração automática do ID
@ColumnConfiguração de coluna
@EnumeratedMapeamento de enum
@OneToOneRelacionamento 1:1
@OneToManyRelacionamento 1:N
@ManyToOneRelacionamento N:1
@ManyToManyRelacionamento N:N
@JoinColumnColuna de junção (FK)
@JoinTableTabela de junção
@QueryConsulta personalizada
@ModifyingConsulta UPDATE/DELETE
@TransactionalGerenciamento de transações
@TransientCampo não persistido

➡️ Capítulo 4: Anotações Security, Teste e Avançadas


⬅️ Voltar ao Módulo 17