Basica

Id

Explorando a anotação @Id do JPA

Explicação

A anotação @Id no JPA (Java Persistence API) é fundamental no mapeamento de entidades para tabelas em um banco de dados relacional. Ela indica que um campo ou propriedade de uma classe é a chave primária (ID) da entidade, ou seja, é o identificador único de cada instância dessa entidade na tabela correspondente no banco de dados.

@Id

Objetivo da anotação @Id

  • Definir a chave primária: O principal objetivo da anotação @Id é identificar o atributo que será utilizado como chave primária de uma entidade. No banco de dados relacional, isso representa a coluna que mantém os valores únicos para identificar cada linha da tabela.
  • Integridade referencial: A chave primária é crucial para garantir a integridade referencial e as relações entre as tabelas.

Requisitos de uso

  • A anotação @Id deve ser aplicada em um único campo ou propriedade de uma classe de entidade.
  • Esse campo ou propriedade precisa ser único e não nulo para garantir a identificação exclusiva de cada instância da entidade.
  • Se o campo não for preenchido ao persistir a entidade, o JPA gerará uma exceção, pois o valor da chave primária é essencial para o processo de inserção.

Tipos de atributos que podem ser anotados com @Id

  • A chave primária pode ser mapeada a partir de diferentes tipos de atributos:
  • Tipos primitivos ou wrappers: Como int, long, Integer, Long, String (geralmente, strings são usadas para UUIDs ou chaves primárias compostas por texto).
  • Objetos complexos: Em algumas situações, você pode usar um tipo de dados mais complexo, como java.util.UUID para identificadores exclusivos.

Papel da chave primária

  • Uniqueness: A chave primária deve ser única dentro da tabela, ou seja, não pode haver duplicidade no valor da chave.
  • Not Null: A chave primária não pode ser null. Ela deve ser obrigatoriamente preenchida.
  • Indexação automática: Em muitos bancos de dados, a chave primária é automaticamente indexada para otimizar as operações de busca e relacionamento entre tabelas.

@GeneratedValue

O JPA permite através do Gerenciamento de Chave Primária que você controle como a chave primária será gerada. Isso pode ser feito por meio de outras anotações, como @GeneratedValue. @GeneratedValue define o mecanismo que será utilizado para gerar o valor da chave primária, como AUTO, IDENTITY, SEQUENCE ou TABLE.

As estratégias de chave primária em JPA são especificadas usando o atributo strategy da anotação @GeneratedValue. Existem quatro estratégias principais de geração de chave primária que você pode usar, e cada uma tem suas particularidades. Elas são:

  1. GenerationType.AUTO

@GenerationType.AUTO

  • Comportamento: O provedor JPA escolhe automaticamente a estratégia mais apropriada para a geração da chave primária com base no banco de dados subjacente.
  • Particularidade: O JPA deixa a decisão sobre como gerar o identificador (usando IDENTITY, SEQUENCE, ou TABLE) ao banco de dados ou ao provedor de persistência.
  • Uso comum: Essa estratégia é útil quando o desenvolvedor não tem uma preferência clara sobre como a chave primária deve ser gerada, e o JPA deve decidir com base no banco de dados.
Cliente.java

import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import java.time.LocalDate;

@Entity
public class Cliente {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Integer id;
}
  1. GenerationType.IDENTITY

@GenerationType.IDENTITY

  • Comportamento: O banco de dados gerencia a geração do identificador, tipicamente usando uma coluna auto-incrementada.
  • Particularidade: O valor da chave primária é gerado pelo banco de dados na hora da inserção da linha. Isso significa que, ao persistir a entidade, o provedor JPA não pode obter o valor da chave primária até que o banco de dados tenha retornado a linha inserida.
  • Banco de dados suportado: Bancos de dados como MySQL, PostgreSQL e SQL Server geralmente suportam essa estratégia.
  • Desvantagens: Em alguns casos, como em sistemas distribuídos ou quando a performance for uma preocupação, o IDENTITY pode ser menos eficiente, pois exige uma ida ao banco de dados para cada inserção (gerando um round-trip para recuperar o valor da chave primária gerada).
Cliente.java

import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import java.time.LocalDate;

@Entity
public class Cliente {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;
}
Resumidamente, @GeneratedValue especifica como o valor da chave primária será gerado.
  1. GenerationType.SEQUENCE
  • Comportamento: O provedor JPA usa uma sequência do banco de dados para gerar os valores de chave primária.
  • Particularidade: Uma sequência é um objeto do banco de dados que gera números sequenciais exclusivos. Em vez de gerar uma chave primária no momento da inserção, o JPA consulta a sequência para obter o próximo valor disponível.
  • Banco de dados suportado: Bancos de dados como Oracle e PostgreSQL são bons exemplos de bancos que suportam esta estratégia. O provedor JPA faz uso de uma sequência no banco de dados para gerar os valores de chave primária.
  • Vantagens: A estratégia SEQUENCE pode ser mais eficiente em termos de desempenho, pois a sequência é gerada de forma independente da operação de inserção. Além disso, pode ser mais eficiente em um cenário distribuído.
Cliente.java

import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import java.time.LocalDate;

@Entity
public class Cliente {
    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "cliente_seq")
    @SequenceGenerator(name = "cliente_seq", sequenceName = "cliente_seq_name", allocationSize = 1)
    private Integer id;
}
@SequenceGenerator pode ser usada para especificar o nome da sequência e outras propriedades, como allocationSize (que define o número de valores a serem alocados de uma vez para evitar acessos excessivos à sequência).
  1. GenerationType.TABLE
  • Comportamento: O JPA usa uma tabela do banco de dados para gerar os valores de chave primária. Em vez de usar um recurso específico do banco, como uma sequência ou um auto-incremento, uma tabela auxilia na geração de chaves.
  • Particularidade: Essa estratégia cria uma tabela adicional no banco de dados que armazena o último valor usado para as chaves primárias. Cada vez que uma nova chave primária é gerada, o JPA consulta essa tabela para obter o próximo valor disponível.
  • Vantagens: Pode ser útil quando o banco de dados não oferece suporte direto para IDENTITY ou SEQUENCE, ou em situações específicas onde você precisa de um controle mais explícito sobre a geração de IDs.
  • Desvantagens: Pode ser menos eficiente do que as outras estratégias, especialmente em bancos de dados com alta carga, pois a tabela de geração de IDs precisa ser acessada constantemente para cada inserção.
Cliente.java

import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import java.time.LocalDate;

@Entity
public class Cliente {
    @Id
    @GeneratedValue(strategy = GenerationType.TABLE, generator = "cliente_gen")
    @TableGenerator(name = "cliente_gen", table = "id_generator", pkColumnName = "gen_name", valueColumnName = "gen_value", allocationSize = 1)
    private Integer id;
}
@TableGenerator especifica a tabela usada para armazenar o valor gerado. Ele define a tabela, o nome da coluna da chave primária e o valor, além de opções como o allocationSize (quantos IDs devem ser gerados de uma vez).

Comparação entre as estratégias

EstratégiaDescriçãoVantagensDesvantagens
AUTOO JPA escolhe a estratégia automática.Simples e conveniente.Menos controle sobre o método de geração.
IDENTITYO banco de dados gera o ID com auto-incremento.Simples e eficiente para a maioria dos bancos de dados.Pode ser mais lento em sistemas distribuídos.
SEQUENCEO banco usa uma sequência para gerar IDs.Mais eficiente em termos de desempenho.Requer suporte da sequência no banco de dados.
TABLEO JPA usa uma tabela auxiliar para gerar IDs.Funciona em qualquer banco de dados.Menos eficiente e exige manutenção de uma tabela extra.

Quando usar cada estratégia?

  • AUTO: Usado quando você não tem uma preferência e deseja que o provedor JPA escolha a melhor estratégia com base no banco de dados.
  • IDENTITY: Usado quando o banco de dados oferece suporte a incremento automático (auto-incremento) de chaves primárias, como em MySQL e SQL Server.
  • SEQUENCE: Usado quando você deseja controle sobre a geração sequencial de IDs, comumente em bancos como Oracle e PostgreSQL.
  • TABLE: Usado quando você precisa de uma estratégia independente de banco de dados ou quando SEQUENCE e IDENTITY não são viáveis.

Conclusão

As estratégias de chave primária em JPA são projetadas para se adaptar ao comportamento de diferentes bancos de dados e cenários de aplicação. A escolha da estratégia de geração de chave primária depende do ambiente de persistência, das necessidades de desempenho e das características do banco de dados utilizado.