JDBC
Insert ID
Database Programming
Java Development
SQL

How to get the insert ID in JDBC?

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

In JDBC, the standard way to retrieve the primary key generated by an INSERT is to execute the statement with Statement.RETURN_GENERATED_KEYS and then read the result from getGeneratedKeys(). This works for both Statement and PreparedStatement, though PreparedStatement is usually the better choice because it is safer and more practical for real applications.

The important part is that you must ask for generated keys when executing the insert. If you do not, many drivers will not provide them afterward.

Use PreparedStatement with RETURN_GENERATED_KEYS

This is the most common and portable JDBC pattern:

java
1import java.sql.*;
2
3public class Main {
4    public static void main(String[] args) throws Exception {
5        String sql = "INSERT INTO employees(name, position) VALUES(?, ?)";
6
7        try (Connection conn = DriverManager.getConnection("jdbc:h2:mem:test");
8             Statement setup = conn.createStatement()) {
9
10            setup.execute("CREATE TABLE employees (id IDENTITY PRIMARY KEY, name VARCHAR(100), position VARCHAR(100))");
11
12            try (PreparedStatement ps = conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS)) {
13                ps.setString(1, "Jane Roe");
14                ps.setString(2, "Analyst");
15
16                int affected = ps.executeUpdate();
17                if (affected == 0) {
18                    throw new SQLException("Insert failed, no rows affected.");
19                }
20
21                try (ResultSet keys = ps.getGeneratedKeys()) {
22                    if (keys.next()) {
23                        long id = keys.getLong(1);
24                        System.out.println("Inserted ID: " + id);
25                    } else {
26                        throw new SQLException("Insert succeeded but no generated key was returned.");
27                    }
28                }
29            }
30        }
31    }
32}

This pattern is usually what you want for auto-increment or identity columns.

Why PreparedStatement Is Usually Better than Statement

A plain Statement can also request generated keys, but PreparedStatement is preferable because it:

  • avoids SQL injection risks
  • handles parameters cleanly
  • is usually easier to maintain
  • works better for repeated inserts

You can technically do this with Statement:

java
Statement stmt = conn.createStatement();
stmt.executeUpdate(sql, Statement.RETURN_GENERATED_KEYS);

But in application code, PreparedStatement should be the default unless you have a strong reason otherwise.

Database and Driver Behavior Still Matter

JDBC standardizes the API shape, but individual drivers vary in detail. Most modern drivers support generated keys for simple auto-generated primary keys, but you should still check driver behavior when:

  • the table uses triggers
  • the key is generated by a sequence in a nonstandard way
  • multiple rows are inserted at once
  • the database prefers RETURNING clauses

In some databases, driver support for generated keys is excellent. In others, a database-specific INSERT ... RETURNING ... query may be cleaner or more reliable.

Multiple Inserts Can Return Multiple Keys

If one execution inserts more than one row, getGeneratedKeys() can return several rows.

java
1try (ResultSet keys = ps.getGeneratedKeys()) {
2    while (keys.next()) {
3        System.out.println("Generated key: " + keys.getLong(1));
4    }
5}

Do not assume there is always exactly one key unless your SQL statement guarantees one inserted row.

You Can Also Ask for Specific Columns

Some JDBC drivers support requesting particular generated columns by name instead of using the general constant.

java
1PreparedStatement ps = conn.prepareStatement(
2    sql,
3    new String[] { "id" }
4);

This can make the intent clearer when a table has more than one generated column or when the driver behaves better with explicit column names.

Check the Row Count First

A subtle but important guard is checking that the insert actually affected a row before reading the generated keys. If the insert failed or inserted zero rows, trying to read a key afterward produces confusing error handling.

That is why the normal control flow is:

  1. execute update
  2. confirm row count
  3. read generated keys

Skipping step two makes troubleshooting harder.

Common Pitfalls

The biggest mistake is calling getGeneratedKeys() without preparing or executing the statement with generated-key support enabled. Another is assuming every JDBC driver behaves identically for every database-specific key strategy. Developers also often forget that multiple inserted rows can produce multiple generated keys, not just one. Finally, using raw Statement string concatenation for inserts is unnecessary and unsafe when PreparedStatement already solves the problem more cleanly.

Summary

  • In JDBC, request generated keys with Statement.RETURN_GENERATED_KEYS.
  • 'PreparedStatement is usually the best way to do this in real code.'
  • Read the key from getGeneratedKeys() after a successful insert.
  • Driver and database behavior can vary, especially for nontrivial key-generation strategies.
  • If your insert affects multiple rows, be prepared to read multiple generated keys.

Course illustration
Course illustration

All Rights Reserved.