LearnAI ToolsCareerPractice BuildsPlayContact
Lesson 1020 min read

Primary Keys & @GeneratedValue

Understand how @GeneratedValue works in Hibernate and the differences between GenerationType.IDENTITY, SEQUENCE, and AUTO.

Introduction

So far, every example manually assigned an id before saving. In real applications, you almost always want the database (or Hibernate) to generate primary keys automatically. This lesson covers @GeneratedValue and the three most common generation strategies: IDENTITY, SEQUENCE, and AUTO.

What You Will Learn
  • Why manually assigning primary keys does not scale.
  • How @GeneratedValue works alongside @Id.
  • The differences between IDENTITY, SEQUENCE, and AUTO.
  • How to choose the right strategy for a given database.

Why Auto-Generate Primary Keys?

Manually assigning IDs, as earlier lessons did, requires the application to track the next available ID itself — a process that is error-prone and breaks down completely with multiple concurrent users. Auto-generation delegates that responsibility to the database or to Hibernate, which can guarantee uniqueness safely.

The Problem With Manual IDs

If two requests both try to manually assign id = 5 at the same time, one insert will fail (or worse, silently overwrite data) due to a primary key collision. Auto-generation avoids this entirely.

@GeneratedValue Basics

@GeneratedValue is paired with @Id and tells Hibernate how to produce a value for the primary key automatically when a new entity is saved.

import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

With this in place, you no longer call student.setId(...) at all — Hibernate populates it after the insert.

GenerationType.IDENTITY

IDENTITY relies on the database's own auto-increment column feature (like MySQL's AUTO_INCREMENT). The database assigns the next value at insert time, and Hibernate reads it back immediately afterward.

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
Generated SQL (MySQL)

Click Run to see what this code prints.

Batching Limitation

IDENTITY requires the insert to happen immediately to retrieve the generated key, which disables Hibernate's JDBC batch inserts for that entity — a real performance consideration for high-volume inserts.

GenerationType.SEQUENCE

SEQUENCE uses a separate database sequence object (supported by PostgreSQL, Oracle, and others — not natively by MySQL) to pre-allocate primary key values. Hibernate can request a batch of values ahead of time, which allows batching inserts efficiently.

import jakarta.persistence.*;
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "student_seq")
@SequenceGenerator(name = "student_seq", sequenceName = "student_sequence", allocationSize = 1)
private Long id;
Generated SQL (PostgreSQL)

Click Run to see what this code prints.

Because the ID is obtained from the sequence before the insert runs, Hibernate can batch multiple inserts together efficiently — a key advantage over IDENTITY for bulk operations.

GenerationType.AUTO

AUTO lets Hibernate pick an appropriate strategy automatically, based on the configured dialect for the target database. It is a convenient default when you do not need to control the exact mechanism.

@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
Note

AUTO is a reasonable default for prototyping or when database portability matters more than fine control, but explicit strategies (IDENTITY or SEQUENCE) give you more predictable, tunable behavior in production systems.

Choosing a Strategy

StrategyBest ForTrade-off
IDENTITYMySQL and databases with native auto-increment support.Disables JDBC insert batching for that entity.
SEQUENCEPostgreSQL, Oracle, and databases with native sequence support.Requires an extra round trip unless allocationSize batching is tuned.
AUTOPrototypes or database-agnostic code.Less explicit and predictable than choosing a strategy directly.

Common Mistakes

Avoid These Mistakes
  • Using GenerationType.SEQUENCE with a database that has no native sequence support, like MySQL.
  • Manually setting an id value on an entity that also uses @GeneratedValue, causing confusing conflicts.
  • Assuming IDENTITY and SEQUENCE perform identically at scale — their batching behavior differs significantly.
  • Forgetting that AUTO's actual behavior depends entirely on the configured dialect.

Best Practices

  • Match the generation strategy to your actual database — IDENTITY for MySQL, SEQUENCE for PostgreSQL/Oracle.
  • For high-volume insert workloads, prefer SEQUENCE where supported, to take advantage of batching.
  • Never manually assign an id on an entity configured with @GeneratedValue.
  • Tune allocationSize on @SequenceGenerator deliberately rather than leaving it at its default for high-throughput systems.

Frequently Asked Questions

GenerationType.IDENTITY is the natural fit, since MySQL supports AUTO_INCREMENT natively and does not support true database sequences.

Hibernate needs the generated key immediately after each insert to keep track of the entity, which forces each insert to execute right away rather than being grouped into a batch.

It is a reasonable starting point, especially for prototypes, but production systems generally benefit from explicitly choosing IDENTITY or SEQUENCE based on the target database.

Yes, though the generation strategies differ — UUID-based keys often use a custom generator rather than IDENTITY or SEQUENCE.

Key Takeaways

  • @GeneratedValue automates primary key assignment, avoiding manual ID management.
  • IDENTITY relies on the database's native auto-increment feature but disables insert batching.
  • SEQUENCE uses a database sequence and supports efficient batched inserts.
  • AUTO lets Hibernate choose a strategy based on the configured dialect.

Summary

Choosing the right primary key generation strategy is a small decision with real performance implications at scale. With entities, mapping annotations, and primary key generation covered, you are ready to move from single saves into full CRUD operations with Hibernate.

Next Lesson →

Basic CRUD with Hibernate