JPA @Id and @GeneratedValue Annotations

In Jakarta Persistence API (JPA), the @Id and @GeneratedValue annotations are essential for defining and generating primary keys for entities. Primary keys uniquely identify each record in a database table, and JPA provides powerful options to automatically generate these keys. 

In this blog post, we will explore the @Id and @GeneratedValue annotations and learn how they work together to manage primary key generation efficiently. 

Understanding JPA @Id Annotation

The @Id annotation marks a field as the primary key of an entity class. It serves as the bridge between the Java object representation and its corresponding database row. Every JPA entity must have a field annotated with @Id to be uniquely identified. 

The field or property to which the @Id annotation is applied should be one of the following types: 
  • any Java primitive type
  • any primitive wrapper type
  • String
  • java.util.Date
  • java.sql.Date
  • java.math.BigDecimal
  • java.math.BigInteger

Defining a Simple Primary Key: 

To create a simple primary key, you can directly apply the @Id annotation to a field in the entity class. 

For example:
import javax.persistence.Entity;
import javax.persistence.Id;

@Entity
public class Student {
    @Id
    private int id;
    private String firstName;
    private String lastName;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getFirstName() {
        return firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }
}
In this case, the field id is designated as the primary key for the Student entity.

Understanding @GeneratedValue Annotation

The @GeneratedValue annotation works in conjunction with @Id to specify how primary key values should be generated. JPA provides several generation strategies to accommodate various database configurations and requirements. 

1. GenerationType.IDENTITY -> Database-Generated Auto-Increment:

@Entity
public class Student {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String firstName;
    private String lastName;
    private String email;

    public Student() {

    }
   // getter and setters
}
This strategy is suitable for databases like MySQL and PostgreSQL that support auto-incrementing columns. The database automatically assigns a unique value to the id field for each new record.

2. GenerationType.SEQUENCE -> Database-Generated Sequence:

@Entity
public class Student {
    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE)
    private Long id;
    private String firstName;
    private String lastName;
    private String email;

    public Student() {

    }
   // getter and setters
}
This strategy is useful for databases like Oracle that have sequence objects. The JPA provider fetches the next sequence value from the database to assign to the id field.

3. GenerationType.TABLE -> Table-Generated Sequence:

@Entity
public class Student {
    @Id
    @GeneratedValue(strategy = GenerationType.TABLE)
    private Long id;
    private String firstName;
    private String lastName;
    private String email;

    public Student() {

    }
   // getter and setters
}
In this strategy, a separate table is used to store and manage the next available primary key values. It provides portability across different databases.

The GenerationType.TABLE gets only rarely used nowadays. It simulates a sequence by storing and updating its current value in a database table which requires the use of pessimistic locks that put all transactions into sequential order. This slows down your application, and you should, therefore, prefer the GenerationType.SEQUENCE, if your database supports sequences, which most popular databases do.

4. GenerationType.AUTO -> Provider-Defined Strategy:

@Entity
public class Student {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;
    private String firstName;
    private String lastName;
    private String email;

    public Student() {

    }
   // getter and setters
}
This strategy allows the JPA provider to choose the most appropriate strategy based on the underlying database and configuration.

5. GenerationType.UUID -> Developer-Defined Strategy:

The latest release of the JPA 3.1.0 specification provides developers with a new GenerationType.UUID we can use in the @GeneratedValue annotation:
@Entity
public class Student {
    @Id
    @GeneratedValue(strategy = GenerationType.UUID)
    private UUID id;
    private String firstName;
    private String lastName;
    private String email;

    public Student() {

    }
   // getter and setters
}
GenerationType instructs that a UUID for the entity should be generated automatically for us by the persistence provider.

Conclusion

The @Id and @GeneratedValue annotations are crucial components of JPA, providing a standardized way to define and generate primary keys. By understanding the various generation strategies and their applications, developers can efficiently manage primary key generation and build robust and scalable JPA-based applications. 

Mastering these annotations empowers Java developers to create sophisticated data models and leverage the full potential of JPA for their database-driven applications.

References

Comments